Skip to content

Commit 1e73f45

Browse files
authored
Merge pull request #197 from DevOpsMadDog/cursor/pr193-consolidate-fixes
Cursor/pr193 consolidate fixes
2 parents 3115ebc + 62518b2 commit 1e73f45

108 files changed

Lines changed: 3909 additions & 2849 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.coverage

-52 KB
Binary file not shown.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,4 @@ coverage.xml
102102
data/data/
103103
real_cve_*.json
104104
terraform.tfvars
105+
.coverage

agents/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
from design-time to runtime, supporting all languages.
55
"""
66

7-
from agents.core.agent_framework import AgentFramework, AgentConfig
7+
from agents.core.agent_framework import AgentConfig, AgentFramework
88
from agents.core.agent_orchestrator import AgentOrchestrator
99
from agents.design_time.code_repo_agent import CodeRepoAgent
10-
from agents.runtime.container_agent import ContainerAgent
11-
from agents.language.python_agent import PythonAgent
12-
from agents.language.javascript_agent import JavaScriptAgent
13-
from agents.language.java_agent import JavaAgent
1410
from agents.language.go_agent import GoAgent
11+
from agents.language.java_agent import JavaAgent
12+
from agents.language.javascript_agent import JavaScriptAgent
13+
from agents.language.python_agent import PythonAgent
14+
from agents.runtime.container_agent import ContainerAgent
1515

1616
__all__ = [
1717
"AgentFramework",

agents/core/agent_framework.py

Lines changed: 53 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
class AgentType(Enum):
2020
"""Agent type categories."""
21-
21+
2222
DESIGN_TIME = "design_time" # Code repos, CI/CD, design tools
2323
RUNTIME = "runtime" # Containers, cloud, APIs
2424
LANGUAGE = "language" # Language-specific agents
@@ -28,7 +28,7 @@ class AgentType(Enum):
2828

2929
class AgentStatus(Enum):
3030
"""Agent status."""
31-
31+
3232
IDLE = "idle"
3333
CONNECTING = "connecting"
3434
MONITORING = "monitoring"
@@ -41,7 +41,7 @@ class AgentStatus(Enum):
4141
@dataclass
4242
class AgentConfig:
4343
"""Agent configuration."""
44-
44+
4545
agent_id: str
4646
agent_type: AgentType
4747
name: str
@@ -57,7 +57,7 @@ class AgentConfig:
5757
@dataclass
5858
class AgentData:
5959
"""Data collected by agent."""
60-
60+
6161
agent_id: str
6262
timestamp: datetime
6363
data_type: str # sarif, sbom, cve, design_context, runtime_metrics, etc.
@@ -67,7 +67,7 @@ class AgentData:
6767

6868
class BaseAgent(ABC):
6969
"""Base class for all FixOps agents."""
70-
70+
7171
def __init__(self, config: AgentConfig, fixops_api_url: str, fixops_api_key: str):
7272
"""Initialize agent."""
7373
self.config = config
@@ -80,77 +80,80 @@ def __init__(self, config: AgentConfig, fixops_api_url: str, fixops_api_key: str
8080
self.collection_count = 0
8181
self.push_count = 0
8282
self._stop_requested = False
83-
83+
8484
@abstractmethod
8585
async def connect(self) -> bool:
8686
"""Connect to target system."""
8787
pass
88-
88+
8989
@abstractmethod
9090
async def disconnect(self):
9191
"""Disconnect from target system."""
9292
pass
93-
93+
9494
@abstractmethod
9595
async def collect_data(self) -> List[AgentData]:
9696
"""Collect data from target system."""
9797
pass
98-
98+
9999
async def push_data(self, data: List[AgentData]) -> bool:
100100
"""Push data to FixOps API."""
101101
import aiohttp
102-
102+
103103
try:
104104
self.status = AgentStatus.PUSHING
105-
105+
106106
async with aiohttp.ClientSession() as session:
107107
for agent_data in data:
108108
# Push to appropriate FixOps endpoint
109109
endpoint = self._get_endpoint(agent_data.data_type)
110110
url = f"{self.fixops_api_url}{endpoint}"
111-
111+
112112
headers = {
113113
"X-API-Key": self.fixops_api_key,
114114
"Content-Type": "application/json",
115115
}
116-
116+
117117
payload = {
118118
"agent_id": agent_data.agent_id,
119119
"timestamp": agent_data.timestamp.isoformat(),
120120
"data_type": agent_data.data_type,
121121
"data": agent_data.data,
122122
"metadata": agent_data.metadata,
123123
}
124-
125-
async with session.post(url, json=payload, headers=headers) as response:
124+
125+
async with session.post(
126+
url, json=payload, headers=headers
127+
) as response:
126128
if response.status not in [200, 201]:
127129
error_text = await response.text()
128130
logger.error(
129131
f"Failed to push {agent_data.data_type} from {self.config.agent_id}: "
130132
f"{response.status} - {error_text}"
131133
)
132134
return False
133-
135+
134136
self.push_count += 1
135137
self.last_push = datetime.now(timezone.utc)
136-
138+
137139
logger.info(
138140
f"Successfully pushed {len(data)} data items from {self.config.agent_id}"
139141
)
140142
return True
141-
143+
142144
except Exception as e:
143145
logger.error(f"Error pushing data from {self.config.agent_id}: {e}")
144146
self.error_count += 1
145147
return False
146-
148+
147149
finally:
148150
if not self._stop_requested:
149151
self.status = AgentStatus.MONITORING
152+
150153
def request_stop(self):
151154
"""Signal the agent to stop after the current iteration."""
152155
self._stop_requested = True
153-
156+
154157
def _get_endpoint(self, data_type: str) -> str:
155158
"""Get FixOps API endpoint for data type."""
156159
endpoints = {
@@ -165,53 +168,53 @@ def _get_endpoint(self, data_type: str) -> str:
165168
"iac_scan": "/api/v1/ingest/iac-scan",
166169
}
167170
return endpoints.get(data_type, "/api/v1/ingest/data")
168-
171+
169172
async def run(self):
170173
"""Main agent loop."""
171174
if not self.config.enabled:
172175
logger.info(f"Agent {self.config.agent_id} is disabled")
173176
return
174-
177+
175178
try:
176179
# Connect
177180
self.status = AgentStatus.CONNECTING
178181
if not await self.connect():
179182
self.status = AgentStatus.ERROR
180183
logger.error(f"Failed to connect agent {self.config.agent_id}")
181184
return
182-
185+
183186
self.status = AgentStatus.MONITORING
184-
187+
185188
# Main monitoring loop
186-
while not self._stop_requested and self.status != AgentStatus.DISCONNECTED:
189+
while not self._stop_requested and self.status != AgentStatus.DISCONNECTED:
187190
try:
188191
# Collect data
189192
self.status = AgentStatus.COLLECTING
190193
data = await self.collect_data()
191194
self.last_collection = datetime.now(timezone.utc)
192195
self.collection_count += len(data)
193-
196+
194197
if data:
195198
# Push data
196199
success = await self.push_data(data)
197200
if not success:
198201
self.error_count += 1
199-
200-
if self._stop_requested:
201-
break
202-
203-
self.status = AgentStatus.MONITORING
204-
202+
203+
if self._stop_requested:
204+
break
205+
206+
self.status = AgentStatus.MONITORING
207+
205208
# Wait for next polling interval
206-
await asyncio.sleep(self.config.polling_interval)
207-
if self._stop_requested:
208-
break
209-
209+
await asyncio.sleep(self.config.polling_interval)
210+
if self._stop_requested:
211+
break
212+
210213
except Exception as e:
211214
logger.error(f"Error in agent {self.config.agent_id} loop: {e}")
212215
self.error_count += 1
213216
self.status = AgentStatus.ERROR
214-
217+
215218
# Retry logic
216219
if self.error_count < self.config.retry_count:
217220
await asyncio.sleep(self.config.retry_delay)
@@ -221,15 +224,15 @@ async def run(self):
221224
f"Agent {self.config.agent_id} exceeded retry count, stopping"
222225
)
223226
break
224-
227+
225228
except Exception as e:
226229
logger.error(f"Fatal error in agent {self.config.agent_id}: {e}")
227230
self.status = AgentStatus.ERROR
228-
231+
229232
finally:
230233
await self.disconnect()
231234
self.status = AgentStatus.DISCONNECTED
232-
235+
233236
def get_status(self) -> Dict[str, Any]:
234237
"""Get agent status."""
235238
return {
@@ -241,9 +244,7 @@ def get_status(self) -> Dict[str, Any]:
241244
"last_collection": (
242245
self.last_collection.isoformat() if self.last_collection else None
243246
),
244-
"last_push": (
245-
self.last_push.isoformat() if self.last_push else None
246-
),
247+
"last_push": (self.last_push.isoformat() if self.last_push else None),
247248
"collection_count": self.collection_count,
248249
"push_count": self.push_count,
249250
"error_count": self.error_count,
@@ -252,41 +253,41 @@ def get_status(self) -> Dict[str, Any]:
252253

253254
class AgentFramework:
254255
"""FixOps Agent Framework - Manages all agents."""
255-
256+
256257
def __init__(self, fixops_api_url: str, fixops_api_key: str):
257258
"""Initialize agent framework."""
258259
self.fixops_api_url = fixops_api_url
259260
self.fixops_api_key = fixops_api_key
260261
self.agents: Dict[str, BaseAgent] = {}
261262
self.running = False
262-
263+
263264
def register_agent(self, agent: BaseAgent):
264265
"""Register an agent."""
265266
self.agents[agent.config.agent_id] = agent
266267
logger.info(f"Registered agent: {agent.config.agent_id}")
267-
268+
268269
async def start_all(self):
269270
"""Start all enabled agents."""
270271
self.running = True
271-
272+
272273
tasks = []
273274
for agent in self.agents.values():
274275
if agent.config.enabled:
275276
task = asyncio.create_task(agent.run())
276277
tasks.append(task)
277-
278+
278279
logger.info(f"Started {len(tasks)} agents")
279280
await asyncio.gather(*tasks, return_exceptions=True)
280-
281+
281282
async def stop_all(self):
282283
"""Stop all agents."""
283284
self.running = False
284-
285+
285286
for agent in self.agents.values():
286287
agent.request_stop()
287-
288+
288289
logger.info("Stopped all agents")
289-
290+
290291
def get_all_status(self) -> List[Dict[str, Any]]:
291292
"""Get status of all agents."""
292293
return [agent.get_status() for agent in self.agents.values()]

0 commit comments

Comments
 (0)