diff --git a/backend/secuscan/database.py b/backend/secuscan/database.py index a830cc5c..79cd75d0 100644 --- a/backend/secuscan/database.py +++ b/backend/secuscan/database.py @@ -839,5 +839,4 @@ async def get_db() -> Database: """Get the global database instance.""" if db is None: raise RuntimeError("Database not initialized") - - return db + return db \ No newline at end of file diff --git a/backend/secuscan/main.py b/backend/secuscan/main.py index e03e9598..52794ac2 100644 --- a/backend/secuscan/main.py +++ b/backend/secuscan/main.py @@ -168,7 +168,6 @@ async def redirect_api_openapi(): app.include_router(router) app.include_router(saved_views_router) - # Health check endpoint @app.get("/api/v1/health") async def health_check(): diff --git a/backend/secuscan/workflows.py b/backend/secuscan/workflows.py index eb98c598..1d250631 100644 --- a/backend/secuscan/workflows.py +++ b/backend/secuscan/workflows.py @@ -9,8 +9,10 @@ from .database import get_db from .config import settings from .executor import executor + from .execution_context import normalize_execution_context from .platform_resources import get_target_policy + logger = logging.getLogger(__name__) class WorkflowScheduler: def __init__(self): @@ -71,6 +73,7 @@ def _should_run(self, now: datetime, last_run_at: str | None, schedule_seconds: elapsed = (now - last).total_seconds() return elapsed >= schedule_seconds async def _run_workflow(self, workflow_id: str, steps: List[Dict[str, Any]]): + db = await get_db() logger.info("Running workflow %s with %d step(s)", workflow_id, len(steps)) for step in steps: plugin_id = step.get("plugin_id") @@ -78,30 +81,36 @@ async def _run_workflow(self, workflow_id: str, steps: List[Dict[str, Any]]): if not plugin_id: continue request_id = get_request_id() - execution_context = normalize_execution_context(step.get("execution_context") or {}) - target_policy = await get_target_policy(db, "default", execution_context.get("target_policy_id")) + execution_context = normalize_execution_context( + step.get("execution_context") or {} + ) + target_policy = await get_target_policy( + db, + "default", + execution_context.get("target_policy_id") + ) safe_mode = bool( settings.safe_mode_default - and not (target_policy and target_policy.get("allow_public_targets")) - ) + and not ( + target_policy + and target_policy.get("allow_public_targets") + ) + ) effective_inputs = dict(inputs) effective_inputs.pop("safe_mode", None) effective_inputs["safe_mode"] = safe_mode task_id = await executor.create_task( - plugin_id, - effective_inputs, - safe_mode=safe_mode, - preset=step.get("preset"), - execution_context=execution_context, - consent_granted=True, - ) - - async def run_task(task_id: str) -> None: + plugin_id, + effective_inputs, + safe_mode=safe_mode, + preset=step.get("preset"), + execution_context=execution_context, + consent_granted=True, + ) + async def run_task(): set_request_id(request_id) await executor.execute_task(task_id) + asyncio.create_task(run_task()) - asyncio.create_task(run_task(task_id)) - - -scheduler = WorkflowScheduler() +scheduler = WorkflowScheduler() \ No newline at end of file diff --git a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx index 6cd5a1da..feff6ebc 100644 --- a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx @@ -108,6 +108,11 @@ describe('ToolConfig dynamic schema flow', () => { }), true, 'quick', + expect.objectContaining({ + evidence_level: 'standard', + scan_profile: 'standard', + validation_mode: 'proof', + }), ) }) }) diff --git a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx index 4c0b2213..513ca033 100644 --- a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx @@ -75,6 +75,6 @@ describe('ToolConfig timeout control', () => { // min from field.validation expect(input).toHaveAttribute('min', '30') // max is min(field.validation.max, server default_timeout) - expect(input).toHaveAttribute('max', '600') + expect(input).toHaveAttribute('max', '7200') }) }) diff --git a/frontend/testing/unit/pages/Workflows.test.tsx b/frontend/testing/unit/pages/Workflows.test.tsx index 7c304da8..b2cc0934 100644 --- a/frontend/testing/unit/pages/Workflows.test.tsx +++ b/frontend/testing/unit/pages/Workflows.test.tsx @@ -17,7 +17,17 @@ const mockWorkflow = { name: 'Nightly Scan', schedule_seconds: 3600, enabled: true, - steps: [{ plugin_id: 'nmap', inputs: {} }], + steps: [ + { + plugin_id: 'nmap', + inputs: {}, + execution_context: { + evidence_level: 'standard'as const, + scan_profile: 'standard', + validation_mode: 'proof' as const, + }, + }, + ], last_run_at: null, queued_task_ids: [], } @@ -130,8 +140,18 @@ describe('Workflows — create action', () => { name: 'Nightly Scan', schedule_seconds: 7200, enabled: true, - steps: [{ plugin_id: '', inputs: {} }], - }) + steps: [ + { + plugin_id: '', + inputs: {}, + execution_context: { + evidence_level: 'standard', + scan_profile: 'standard', + validation_mode: 'proof' as const, + }, + }, + ], + }) }) })