fix: remove stack-trace exposure in exception handlers
Some checks failed
Cross-Node Transaction Testing / transaction-test (push) Has been cancelled
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Node Failover Simulation / failover-test (push) Has been cancelled
API Endpoint Tests / test-api-endpoints (push) Failing after 18m8s
Integration Tests / test-service-integration (push) Failing after 54s
Production Tests / Production Integration Tests (push) Successful in 21s
Python Tests / test-python (push) Failing after 1m13s
Security Scanning / security-scan (push) Successful in 40s

- Add logging to multi_modal_rl.py and log errors instead of exposing exception details
- Log NetworkError exceptions in blockchain.py instead of exposing exception details
- Replace str(e) with generic error messages in consensus.py exception handlers
- Replace str(e) with generic error messages in users.py exception handlers
- Fixes py/stack-trace-exposure security alerts
This commit is contained in:
aitbc
2026-05-05 17:23:32 +02:00
parent ce750b46ca
commit 43c1919318
4 changed files with 51 additions and 29 deletions

View File

@@ -32,7 +32,7 @@ async def register_consensus_node(node_data: Dict[str, Any]):
return result
except Exception as e:
logger.error(f"Error registering consensus node: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to register consensus node")
@router.post("/consensus/proposal/create")
async def create_consensus_proposal(proposal_data: Dict[str, Any]):
@@ -42,7 +42,7 @@ async def create_consensus_proposal(proposal_data: Dict[str, Any]):
return result
except Exception as e:
logger.error(f"Error creating consensus proposal: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to create consensus proposal")
@router.post("/consensus/proposal/{proposal_id}/vote")
async def cast_consensus_vote(proposal_id: str, node_id: str, vote: bool):
@@ -52,7 +52,7 @@ async def cast_consensus_vote(proposal_id: str, node_id: str, vote: bool):
return result
except Exception as e:
logger.error(f"Error casting consensus vote: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to cast consensus vote")
@router.get("/consensus/proposal/{proposal_id}")
async def get_proposal_status(proposal_id: str):
@@ -62,7 +62,7 @@ async def get_proposal_status(proposal_id: str):
return result
except Exception as e:
logger.error(f"Error getting proposal status: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to get proposal status")
@router.put("/consensus/algorithm")
async def set_consensus_algorithm(algorithm: str = Query(..., description="Consensus algorithm")):
@@ -72,7 +72,7 @@ async def set_consensus_algorithm(algorithm: str = Query(..., description="Conse
return result
except Exception as e:
logger.error(f"Error setting consensus algorithm: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to set consensus algorithm")
@router.get("/consensus/statistics")
async def get_consensus_statistics():
@@ -82,7 +82,7 @@ async def get_consensus_statistics():
return result
except Exception as e:
logger.error(f"Error getting consensus statistics: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to get consensus statistics")
@router.put("/consensus/node/{node_id}/status")
async def update_node_status(node_id: str, is_active: bool):
@@ -92,7 +92,7 @@ async def update_node_status(node_id: str, is_active: bool):
return result
except Exception as e:
logger.error(f"Error updating node status: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to update node status")
# Advanced features status endpoint
@router.get("/advanced-features/status")
@@ -130,4 +130,4 @@ async def get_advanced_features_status():
}
except Exception as e:
logger.error(f"Error getting advanced features status: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to get advanced features status")

View File

@@ -190,7 +190,7 @@ async def get_role_permissions(
raise
except Exception as e:
logger.error(f"Error getting role permissions: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to get role permissions")
@router.get("/auth/stats")
async def get_permission_stats(current_user: Dict[str, Any] = Depends(get_current_user)):
@@ -208,7 +208,7 @@ async def get_permission_stats(current_user: Dict[str, Any] = Depends(get_curren
raise
except Exception as e:
logger.error(f"Error getting permission stats: {e}")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail="Failed to get permission stats")
# Protected endpoint example
@router.get("/protected/admin")

View File

@@ -58,7 +58,8 @@ async def blockchain_sync_status() -> dict[str, Any]:
else:
return {"status": "synced", "block": response.get("current_block", 0)}
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
except Exception as e:
return {"status": "error", "error": "Failed to get sync status"}
@@ -73,7 +74,8 @@ async def get_block(height: int) -> dict[str, Any]:
response = client.get(f"{rpc_url}/rpc/blocks/{height}")
return response
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
@router.get("/blocks/hash/{block_hash}")
@@ -87,7 +89,8 @@ async def get_block_by_hash(block_hash: str) -> dict[str, Any]:
response = client.get(f"{rpc_url}/rpc/blocks/hash/{block_hash}")
return response
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
@router.get("/transactions/{tx_hash}")
@@ -101,7 +104,8 @@ async def get_transaction(tx_hash: str) -> dict[str, Any]:
response = client.get(f"{rpc_url}/rpc/transactions/{tx_hash}")
return response
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
@router.get("/accounts/{address}")
@@ -115,7 +119,8 @@ async def get_account(address: str) -> dict[str, Any]:
response = client.get(f"{rpc_url}/rpc/accounts/{address}")
return response
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
@router.get("/validators")
@@ -134,7 +139,8 @@ async def get_validators() -> dict[str, Any]:
"total": 1
}
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
@router.get("/supply")
@@ -155,7 +161,8 @@ async def get_supply() -> dict[str, Any]:
"unit": "AIT"
}
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}
@router.get("/state/dump")
@@ -173,4 +180,5 @@ async def get_state_dump() -> dict[str, Any]:
"timestamp": response.get("timestamp", "")
}
except NetworkError as e:
return {"status": "error", "error": f"RPC connection failed: {e}"}
logger.error(f"RPC connection failed: {e}")
return {"status": "error", "error": "RPC connection failed"}

View File

@@ -3,6 +3,7 @@ Multi-modal RL Router
Handles multi-modal reinforcement learning endpoints by proxying to AI service
"""
import logging
from typing import Any
from fastapi import APIRouter
@@ -10,6 +11,8 @@ from pydantic import BaseModel
from aitbc import AITBCHTTPClient, NetworkError
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/multi-modal-rl", tags=["multi-modal-rl"])
@@ -45,9 +48,11 @@ async def submit_job(req: JobCreate, client_id: str = "default_client") -> dict[
response = client.post(f"{ai_url}/jobs", json=job_data)
return response
except NetworkError as e:
return {"error": f"AI service connection failed: {e}"}
logger.error(f"AI service connection failed: {e}")
return {"error": "AI service connection failed"}
except Exception as e:
return {"error": f"Failed to submit job: {e}"}
logger.error(f"Failed to submit job: {e}")
return {"error": "Failed to submit job"}
@router.get("/jobs/{job_id}")
@@ -59,9 +64,11 @@ async def get_job(job_id: str, client_id: str = "default_client") -> dict[str, A
response = client.get(f"{ai_url}/jobs/{job_id}", params={"client_id": client_id})
return response
except NetworkError as e:
return {"error": f"AI service connection failed: {e}"}
logger.error(f"AI service connection failed: {e}")
return {"error": "AI service connection failed"}
except Exception as e:
return {"error": f"Failed to get job: {e}"}
logger.error(f"Failed to get job: {e}")
return {"error": "Failed to get job"}
@router.get("/jobs/{job_id}/result")
@@ -73,9 +80,11 @@ async def get_job_result(job_id: str, client_id: str = "default_client") -> dict
response = client.get(f"{ai_url}/jobs/{job_id}/result", params={"client_id": client_id})
return response
except NetworkError as e:
return {"error": f"AI service connection failed: {e}"}
logger.error(f"AI service connection failed: {e}")
return {"error": "AI service connection failed"}
except Exception as e:
return {"error": f"Failed to get job result: {e}"}
logger.error(f"Failed to get job result: {e}")
return {"error": "Failed to get job result"}
@router.post("/jobs/{job_id}/cancel")
@@ -87,9 +96,11 @@ async def cancel_job(job_id: str, client_id: str = "default_client") -> dict[str
response = client.post(f"{ai_url}/jobs/{job_id}/cancel", params={"client_id": client_id})
return response
except NetworkError as e:
return {"error": f"AI service connection failed: {e}"}
logger.error(f"AI service connection failed: {e}")
return {"error": "AI service connection failed"}
except Exception as e:
return {"error": f"Failed to cancel job: {e}"}
logger.error(f"Failed to cancel job: {e}")
return {"error": "Failed to cancel job"}
@router.get("/jobs")
@@ -104,9 +115,11 @@ async def list_jobs(client_id: str = "default_client", limit: int = 10, state: s
response = client.get(f"{ai_url}/jobs", params=params)
return response
except NetworkError as e:
return {"error": f"AI service connection failed: {e}"}
logger.error(f"AI service connection failed: {e}")
return {"error": "AI service connection failed"}
except Exception as e:
return {"error": f"Failed to list jobs: {e}"}
logger.error(f"Failed to list jobs: {e}")
return {"error": "Failed to list jobs"}
@router.get("/health")
@@ -128,7 +141,8 @@ async def health() -> dict[str, Any]:
"ai_service": "unreachable",
"note": "AI service not available on this node"
}
except Exception:
except Exception as e:
logger.error(f"AI service check failed: {e}")
return {
"status": "degraded",
"router": "multi-modal-rl",