Skip to content

Commit ca32799

Browse files
committed
Merge remote-tracking branch 'origin/main' into main
Resolved conflicts favoring local changes: - Kept our deletions (scan_config_api.py, scans/mongodb.py, scans_routes.py, auth_service.py) - Kept our modifications to main.py, scans/compliance.py, scans/config.py, scans/models.py - Remote had Black formatting changes that conflicted with our refactoring Our changes take precedence as they represent functional refactoring (E1-S1, E1-S2, E1-S3).
2 parents d7ef2e4 + fbe8429 commit ca32799

34 files changed

Lines changed: 831 additions & 259 deletions

backend/app/routes/compliance/drift.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ class DriftEventsListResponse(BaseModel):
8888
)
8989
async def list_drift_events(
9090
host_id: Optional[UUID] = Query(None, description="Filter by host ID"),
91-
drift_type: Optional[str] = Query(None, description="Filter by drift type (major, minor, improvement, stable)"),
91+
drift_type: Optional[str] = Query(
92+
None, description="Filter by drift type (major, minor, improvement, stable)"
93+
),
9294
exclude_stable: bool = Query(False, description="Exclude stable drift events"),
9395
limit: int = Query(10, ge=1, le=100, description="Maximum number of events to return"),
9496
offset: int = Query(0, ge=0, description="Number of events to skip"),
@@ -142,7 +144,9 @@ async def list_drift_events(
142144
builder.where("sde.drift_type != :stable", "stable", "stable")
143145

144146
# Get total count
145-
count_builder = QueryBuilder("scan_drift_events sde").join("hosts h", "h.id = sde.host_id", "INNER")
147+
count_builder = QueryBuilder("scan_drift_events sde").join(
148+
"hosts h", "h.id = sde.host_id", "INNER"
149+
)
146150
if host_id:
147151
count_builder.where("sde.host_id = :host_id", host_id, "host_id")
148152
if drift_type:

backend/app/routes/compliance/intelligence.py

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ class ComplianceOverview(BaseModel):
9898
async def get_semantic_rules(
9999
framework: Optional[str] = Query(None, description="Filter by framework"),
100100
business_impact: Optional[str] = Query(None, description="Filter by business impact"),
101-
remediation_available: Optional[bool] = Query(None, description="Filter by remediation availability"),
101+
remediation_available: Optional[bool] = Query(
102+
None, description="Filter by remediation availability"
103+
),
102104
db: Session = Depends(get_db),
103105
current_user: Dict[str, Any] = Depends(get_current_user),
104106
) -> Dict[str, Any]:
@@ -149,7 +151,9 @@ async def get_semantic_rules(
149151
"remediation_complexity": rule.remediation_complexity,
150152
"estimated_fix_time": rule.estimated_fix_time,
151153
"remediation_available": rule.remediation_available,
152-
"confidence_score": (float(rule.confidence_score) if rule.confidence_score else 1.0),
154+
"confidence_score": (
155+
float(rule.confidence_score) if rule.confidence_score else 1.0
156+
),
153157
}
154158
)
155159

@@ -220,7 +224,9 @@ async def get_framework_intelligence(
220224

221225
remediation_coverage = 0
222226
if stats.rule_count > 0:
223-
remediation_coverage = round((stats.remediation_available_count / stats.rule_count) * 100)
227+
remediation_coverage = round(
228+
(stats.remediation_available_count / stats.rule_count) * 100
229+
)
224230

225231
frameworks.append(
226232
{
@@ -307,7 +313,9 @@ async def get_compliance_overview(
307313

308314
except Exception as e:
309315
logger.error(f"Error retrieving compliance overview: {e}")
310-
raise HTTPException(status_code=500, detail=f"Failed to retrieve compliance overview: {str(e)}")
316+
raise HTTPException(
317+
status_code=500, detail=f"Failed to retrieve compliance overview: {str(e)}"
318+
)
311319

312320

313321
@router.get("/semantic-analysis/{scan_id}")
@@ -337,9 +345,13 @@ async def get_semantic_analysis(
337345
"scan_id": str(analysis.scan_id),
338346
"host_id": str(analysis.host_id),
339347
"semantic_rules_count": analysis.semantic_rules_count,
340-
"frameworks_analyzed": (json.loads(analysis.frameworks_analyzed) if analysis.frameworks_analyzed else []),
348+
"frameworks_analyzed": (
349+
json.loads(analysis.frameworks_analyzed) if analysis.frameworks_analyzed else []
350+
),
341351
"remediation_available_count": analysis.remediation_available_count,
342-
"processing_metadata": (json.loads(analysis.processing_metadata) if analysis.processing_metadata else {}),
352+
"processing_metadata": (
353+
json.loads(analysis.processing_metadata) if analysis.processing_metadata else {}
354+
),
343355
"analysis_data": (json.loads(analysis.analysis_data) if analysis.analysis_data else {}),
344356
"created_at": (analysis.created_at.isoformat() if analysis.created_at else None),
345357
"updated_at": (analysis.updated_at.isoformat() if analysis.updated_at else None),
@@ -349,7 +361,9 @@ async def get_semantic_analysis(
349361
raise
350362
except Exception as e:
351363
logger.error(f"Error retrieving semantic analysis: {e}")
352-
raise HTTPException(status_code=500, detail=f"Failed to retrieve semantic analysis: {str(e)}")
364+
raise HTTPException(
365+
status_code=500, detail=f"Failed to retrieve semantic analysis: {str(e)}"
366+
)
353367

354368

355369
@router.get("/compliance-matrix")
@@ -386,16 +400,22 @@ async def get_compliance_matrix(
386400
{
387401
"host_id": str(row.host_id),
388402
"framework": row.framework,
389-
"compliance_score": (float(row.compliance_score) if row.compliance_score else 0.0),
403+
"compliance_score": (
404+
float(row.compliance_score) if row.compliance_score else 0.0
405+
),
390406
"total_rules": row.total_rules,
391407
"passed_rules": row.passed_rules,
392408
"failed_rules": row.failed_rules,
393409
"previous_score": (float(row.previous_score) if row.previous_score else None),
394410
"trend": row.trend,
395411
"last_scan_id": str(row.last_scan_id) if row.last_scan_id else None,
396412
"last_updated": (row.last_updated.isoformat() if row.last_updated else None),
397-
"predicted_next_score": (float(row.predicted_next_score) if row.predicted_next_score else None),
398-
"prediction_confidence": (float(row.prediction_confidence) if row.prediction_confidence else None),
413+
"predicted_next_score": (
414+
float(row.predicted_next_score) if row.predicted_next_score else None
415+
),
416+
"prediction_confidence": (
417+
float(row.prediction_confidence) if row.prediction_confidence else None
418+
),
399419
}
400420
)
401421

@@ -407,7 +427,9 @@ async def get_compliance_matrix(
407427

408428
except Exception as e:
409429
logger.error(f"Error retrieving compliance matrix: {e}")
410-
raise HTTPException(status_code=500, detail=f"Failed to retrieve compliance matrix: {str(e)}")
430+
raise HTTPException(
431+
status_code=500, detail=f"Failed to retrieve compliance matrix: {str(e)}"
432+
)
411433

412434

413435
@router.post("/remediation/strategy")
@@ -468,7 +490,9 @@ async def create_remediation_strategy(
468490
raise
469491
except Exception as e:
470492
logger.error(f"Error creating remediation strategy: {e}")
471-
raise HTTPException(status_code=500, detail=f"Failed to create remediation strategy: {str(e)}")
493+
raise HTTPException(
494+
status_code=500, detail=f"Failed to create remediation strategy: {str(e)}"
495+
)
472496

473497

474498
@router.get("/health")

backend/app/routes/compliance/owca.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ async def get_host_framework_intelligence(
256256
"""
257257
try:
258258
owca = get_owca_service(db)
259-
intelligence = await owca.get_framework_intelligence(framework=framework, host_id=str(host_id))
259+
intelligence = await owca.get_framework_intelligence(
260+
framework=framework, host_id=str(host_id)
261+
)
260262

261263
if not intelligence:
262264
raise HTTPException(
@@ -269,7 +271,9 @@ async def get_host_framework_intelligence(
269271
if hasattr(intelligence, "dict"):
270272
result = dict(intelligence.dict())
271273
else:
272-
result = dict(intelligence) if isinstance(intelligence, dict) else {"data": intelligence}
274+
result = (
275+
dict(intelligence) if isinstance(intelligence, dict) else {"data": intelligence}
276+
)
273277
return result
274278

275279
except HTTPException:
@@ -442,7 +446,9 @@ async def calculate_host_risk(
442446
description="Get all hosts ranked by risk score for prioritization",
443447
)
444448
async def rank_fleet_by_risk(
445-
limit: Optional[int] = Query(None, ge=1, le=100, description="Maximum number of hosts to return"),
449+
limit: Optional[int] = Query(
450+
None, ge=1, le=100, description="Maximum number of hosts to return"
451+
),
446452
db: Session = Depends(get_db),
447453
_current_user: Dict[str, Any] = Depends(get_current_user),
448454
) -> List[Dict[str, Any]]:
@@ -496,7 +502,9 @@ async def forecast_host_compliance(
496502
"""
497503
try:
498504
owca = get_owca_service(db)
499-
forecast = await owca.forecast_compliance(str(host_id), entity_type="host", days_ahead=days_ahead)
505+
forecast = await owca.forecast_compliance(
506+
str(host_id), entity_type="host", days_ahead=days_ahead
507+
)
500508

501509
if not forecast:
502510
raise HTTPException(
@@ -505,7 +513,9 @@ async def forecast_host_compliance(
505513
)
506514

507515
# Convert to dict with proper type annotation
508-
result: Dict[str, Any] = dict(forecast.dict()) if hasattr(forecast, "dict") else dict(forecast)
516+
result: Dict[str, Any] = (
517+
dict(forecast.dict()) if hasattr(forecast, "dict") else dict(forecast)
518+
)
509519
return result
510520

511521
except HTTPException:
@@ -523,7 +533,9 @@ async def forecast_host_compliance(
523533
)
524534
async def detect_host_anomalies(
525535
host_id: UUID,
526-
lookback_days: int = Query(60, ge=30, le=180, description="Days of history to analyze (30-180)"),
536+
lookback_days: int = Query(
537+
60, ge=30, le=180, description="Days of history to analyze (30-180)"
538+
),
527539
db: Session = Depends(get_db),
528540
_current_user: Dict[str, Any] = Depends(get_current_user),
529541
) -> List[Dict[str, Any]]:
@@ -542,7 +554,9 @@ async def detect_host_anomalies(
542554
"""
543555
try:
544556
owca = get_owca_service(db)
545-
anomalies = await owca.detect_anomalies(str(host_id), entity_type="host", lookback_days=lookback_days)
557+
anomalies = await owca.detect_anomalies(
558+
str(host_id), entity_type="host", lookback_days=lookback_days
559+
)
546560

547561
return [anomaly.dict() if hasattr(anomaly, "dict") else anomaly for anomaly in anomalies]
548562

backend/app/routes/drift_events.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ class DriftEventsListResponse(BaseModel):
7474
)
7575
async def list_drift_events(
7676
host_id: Optional[UUID] = Query(None, description="Filter by host ID"),
77-
drift_type: Optional[str] = Query(None, description="Filter by drift type (major, minor, improvement, stable)"),
77+
drift_type: Optional[str] = Query(
78+
None, description="Filter by drift type (major, minor, improvement, stable)"
79+
),
7880
exclude_stable: bool = Query(False, description="Exclude stable drift events"),
7981
limit: int = Query(10, ge=1, le=100, description="Maximum number of events to return"),
8082
offset: int = Query(0, ge=0, description="Number of events to skip"),
@@ -128,7 +130,9 @@ async def list_drift_events(
128130
builder.where("sde.drift_type != :stable", "stable", "stable")
129131

130132
# Get total count
131-
count_builder = QueryBuilder("scan_drift_events sde").join("hosts h", "h.id = sde.host_id", "INNER")
133+
count_builder = QueryBuilder("scan_drift_events sde").join(
134+
"hosts h", "h.id = sde.host_id", "INNER"
135+
)
132136
if host_id:
133137
count_builder.where("sde.host_id = :host_id", host_id, "host_id")
134138
if drift_type:

backend/app/routes/host_compliance_discovery_legacy.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,14 @@ async def discover_host_compliance_infrastructure(
9797

9898
# Perform compliance discovery
9999
compliance_service = HostComplianceDiscoveryService()
100-
discovery_results: Dict[str, Any] = compliance_service.discover_compliance_infrastructure(host)
100+
discovery_results: Dict[str, Any] = compliance_service.discover_compliance_infrastructure(
101+
host
102+
)
101103

102104
# Convert datetime to string for JSON serialization
103-
discovery_results["discovery_timestamp"] = discovery_results["discovery_timestamp"].isoformat()
105+
discovery_results["discovery_timestamp"] = discovery_results[
106+
"discovery_timestamp"
107+
].isoformat()
104108

105109
logger.info(
106110
f"Compliance discovery completed for host {host.hostname}: "
@@ -178,7 +182,9 @@ async def bulk_discover_compliance_infrastructure(
178182
discovery_results = compliance_service.discover_compliance_infrastructure(host)
179183

180184
# Convert datetime to string for JSON serialization
181-
discovery_results["discovery_timestamp"] = discovery_results["discovery_timestamp"].isoformat()
185+
discovery_results["discovery_timestamp"] = discovery_results[
186+
"discovery_timestamp"
187+
].isoformat()
182188

183189
results[host_id] = ComplianceDiscoveryResponse(**discovery_results)
184190

@@ -330,7 +336,9 @@ async def get_supported_compliance_frameworks(
330336
return frameworks
331337

332338

333-
def _assess_compliance_capabilities(host: Host, discovery_results: Dict[str, Any]) -> ComplianceCapabilityAssessment:
339+
def _assess_compliance_capabilities(
340+
host: Host, discovery_results: Dict[str, Any]
341+
) -> ComplianceCapabilityAssessment:
334342
"""Assess host's compliance capabilities based on discovery results"""
335343

336344
# Assess SCAP capability

backend/app/routes/host_discovery_legacy.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ async def discover_basic_system_bulk(
134134
if host.username and (host.ip_address or host.hostname):
135135
valid_hosts.append(host)
136136
else:
137-
invalid_hosts.append({"host_id": host_id, "error": "Missing connection information"})
137+
invalid_hosts.append(
138+
{"host_id": host_id, "error": "Missing connection information"}
139+
)
138140
else:
139141
invalid_hosts.append({"host_id": host_id, "error": "Host not found"})
140142

@@ -155,7 +157,9 @@ async def discover_basic_system_bulk(
155157

156158
except Exception as e:
157159
logger.error(f"Failed to schedule discovery for host {host.id}: {str(e)}")
158-
invalid_hosts.append({"host_id": str(host.id), "error": f"Failed to schedule: {str(e)}"})
160+
invalid_hosts.append(
161+
{"host_id": str(host.id), "error": f"Failed to schedule: {str(e)}"}
162+
)
159163

160164
# Estimate completion time (assume 30 seconds per host)
161165
estimated_completion = datetime.utcnow()

0 commit comments

Comments
 (0)