|
20 | 20 | from typing import Optional |
21 | 21 |
|
22 | 22 | # Third-Party |
23 | | -from fastapi import APIRouter, Depends, Form, HTTPException, status |
| 23 | +from fastapi import APIRouter, Depends, Form, HTTPException, Request, status |
| 24 | +from mcpgateway.auth import get_current_user |
24 | 25 | from fastapi.responses import HTMLResponse |
25 | 26 | from sqlalchemy.orm import Session |
26 | 27 |
|
27 | 28 | # Local |
28 | 29 | from ..db import get_db |
29 | | -from ..schemas.sandbox import ( |
| 30 | +from ..schemas import ( |
30 | 31 | BatchSimulateRequest, |
31 | 32 | BatchSimulationResult, |
32 | 33 | RegressionReport, |
@@ -505,6 +506,8 @@ async def service_info() -> dict: |
505 | 506 |
|
506 | 507 | @router.post("/sandbox/simulate", response_class=HTMLResponse) |
507 | 508 | async def simulate_form_submit( |
| 509 | + request: Request, |
| 510 | + current_user=Depends(get_current_user), |
508 | 511 | policy_draft_id: str = Form(...), |
509 | 512 | subject_email: str = Form(...), |
510 | 513 | subject_roles: str = Form(...), |
@@ -554,96 +557,13 @@ async def simulate_form_submit( |
554 | 557 | include_explanation=True, |
555 | 558 | ) |
556 | 559 |
|
557 | | - # Generate HTML response |
558 | | - passed_class = "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200" if result.passed else "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200" |
559 | | - passed_text = "PASSED ✓" if result.passed else "FAILED ✗" |
560 | | - |
561 | | - policies_html = "".join( |
562 | | - [ |
563 | | - f'<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">{policy}</span>' |
564 | | - for policy in result.matching_policies |
565 | | - ] |
| 560 | + # Render template response with auto-escaping |
| 561 | + return request.app.state.templates.TemplateResponse( |
| 562 | + request, |
| 563 | + "sandbox_simulate_results.html", |
| 564 | + {"result": result} |
566 | 565 | ) |
567 | 566 |
|
568 | | - explanation_html = "" |
569 | | - if result.explanation: |
570 | | - explanation_html = f""" |
571 | | - <div class="border-t border-gray-200 dark:border-gray-700 pt-6"> |
572 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-3">Detailed Explanation</h4> |
573 | | - <div class="bg-gray-50 dark:bg-gray-900 rounded-md p-4"> |
574 | | - <pre class="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap font-mono">{result.explanation}</pre> |
575 | | - </div> |
576 | | - </div> |
577 | | - """ |
578 | | - |
579 | | - html = f""" |
580 | | - <div class="bg-white dark:bg-gray-800 shadow rounded-lg"> |
581 | | - <div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700"> |
582 | | - <h3 class="text-lg font-semibold text-gray-900 dark:text-white"> |
583 | | - Simulation Results |
584 | | - </h3> |
585 | | - </div> |
586 | | -
|
587 | | - <div class="p-6 space-y-6"> |
588 | | - <!-- Result Badge --> |
589 | | - <div class="flex items-center justify-between"> |
590 | | - <div> |
591 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400">Test Result</h4> |
592 | | - <div class="mt-2"> |
593 | | - <span class="px-3 py-1 inline-flex text-sm leading-5 font-semibold rounded-full {passed_class}"> |
594 | | - {passed_text} |
595 | | - </span> |
596 | | - </div> |
597 | | - </div> |
598 | | - <div class="text-right"> |
599 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400">Execution Time</h4> |
600 | | - <p class="mt-2 text-2xl font-bold text-gray-900 dark:text-white"> |
601 | | - {result.execution_time_ms}ms |
602 | | - </p> |
603 | | - </div> |
604 | | - </div> |
605 | | -
|
606 | | - <!-- Decision Details --> |
607 | | - <div class="grid grid-cols-1 md:grid-cols-2 gap-6 border-t border-gray-200 dark:border-gray-700 pt-6"> |
608 | | - <div> |
609 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Expected Decision</h4> |
610 | | - <p class="text-lg font-semibold text-gray-900 dark:text-white"> |
611 | | - {result.expected_decision.value} |
612 | | - </p> |
613 | | - </div> |
614 | | - <div> |
615 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Actual Decision</h4> |
616 | | - <p class="text-lg font-semibold text-gray-900 dark:text-white"> |
617 | | - {result.actual_decision.value} |
618 | | - </p> |
619 | | - </div> |
620 | | - </div> |
621 | | -
|
622 | | - <!-- Matching Policies --> |
623 | | - <div class="border-t border-gray-200 dark:border-gray-700 pt-6"> |
624 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-3">Matching Policies</h4> |
625 | | - <div class="space-x-2 space-y-2"> |
626 | | - {policies_html if policies_html else '<p class="text-sm text-gray-500 dark:text-gray-400">No policies matched</p>'} |
627 | | - </div> |
628 | | - </div> |
629 | | -
|
630 | | - <!-- Reason --> |
631 | | - <div class="border-t border-gray-200 dark:border-gray-700 pt-6"> |
632 | | - <h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-3">Decision Reason</h4> |
633 | | - <div class="bg-gray-50 dark:bg-gray-900 rounded-md p-4"> |
634 | | - <p class="text-sm text-gray-700 dark:text-gray-300"> |
635 | | - {result.reason} |
636 | | - </p> |
637 | | - </div> |
638 | | - </div> |
639 | | -
|
640 | | - {explanation_html} |
641 | | - </div> |
642 | | - </div> |
643 | | - """ |
644 | | - |
645 | | - return HTMLResponse(content=html) |
646 | | - |
647 | 567 | except Exception as e: |
648 | 568 | logger.exception("Error running simulation") |
649 | 569 | error_html = f""" |
|
0 commit comments