From 320004940c14050943febd527760ae597a1352c5 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 6 Jun 2026 13:14:16 +0530 Subject: [PATCH 1/2] fix(ci): resolve backend lint F821 and stale frontend test mocks Two separate CI regressions were introduced by commits 0e03877 and a2a7e02: Backend lint (F821 - Undefined name 'db') workflows.py._run_workflow() calls get_target_policy(db, ...) but 'db' was never acquired in that method. tick() obtains 'db' but does not pass it into _run_workflow(). Fixed by adding db = await get_db() at the top of _run_workflow(). Frontend unit test failures (3 tests) ToolConfig.tsx now calls listTargetPolicies(), listCredentialProfiles(), and listSessionProfiles() inside its useEffect via Promise.all. Tests that only mocked the original 3-4 API functions caused Promise.all to reject (unmocked vi.fn() returns undefined, not a Promise), making setServerLimits never execute and breaking max/min attribute assertions. Workflows.tsx changed emptySteps to include an execution_context object in each step. The createWorkflow assertion expected the old shape. Fixes applied: - ToolConfigDynamic.test.tsx: add listTargetPolicies, listCredentialProfiles, listSessionProfiles, getSettings to vi.mock factory and beforeEach mocks; update startTask assertion to accept the new 5th executionContext argument - ToolConfigTimeout.test.tsx: add the three new API functions to vi.mock factory and beforeEach mocks so Promise.all resolves correctly - Workflows.test.tsx: update createWorkflow expectation to include execution_context in the steps array --- backend/secuscan/workflows.py | 1 + .../testing/unit/pages/ToolConfigDynamic.test.tsx | 11 ++++++++++- .../testing/unit/pages/ToolConfigTimeout.test.tsx | 8 +++++++- frontend/testing/unit/pages/Workflows.test.tsx | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/secuscan/workflows.py b/backend/secuscan/workflows.py index eb98c598..c7ba88dc 100644 --- a/backend/secuscan/workflows.py +++ b/backend/secuscan/workflows.py @@ -72,6 +72,7 @@ def _should_run(self, now: datetime, last_run_at: str | None, schedule_seconds: return elapsed >= schedule_seconds async def _run_workflow(self, workflow_id: str, steps: List[Dict[str, Any]]): logger.info("Running workflow %s with %d step(s)", workflow_id, len(steps)) + db = await get_db() for step in steps: plugin_id = step.get("plugin_id") inputs = step.get("inputs") or {} diff --git a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx index 6cd5a1da..9b53b37b 100644 --- a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx @@ -2,7 +2,7 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { MemoryRouter, Route, Routes } from 'react-router-dom' import ToolConfig from '../../../src/pages/ToolConfig' -import { getPluginSchema, listPlugins, startTask } from '../../../src/api' +import { getPluginSchema, listPlugins, startTask, getSettings, listTargetPolicies, listCredentialProfiles, listSessionProfiles } from '../../../src/api' import { routes } from '../../../src/routes' const addToast = vi.fn() @@ -15,6 +15,10 @@ vi.mock('../../../src/api', () => ({ listPlugins: vi.fn(), getPluginSchema: vi.fn(), startTask: vi.fn(), + getSettings: vi.fn(), + listTargetPolicies: vi.fn(), + listCredentialProfiles: vi.fn(), + listSessionProfiles: vi.fn(), })) describe('ToolConfig dynamic schema flow', () => { @@ -74,6 +78,10 @@ describe('ToolConfig dynamic schema flow', () => { created_at: 'now', stream_url: '/api/v1/task/task-123/stream', }) + vi.mocked(getSettings).mockResolvedValue(null) + vi.mocked(listTargetPolicies).mockResolvedValue({ items: [] }) + vi.mocked(listCredentialProfiles).mockResolvedValue({ items: [] }) + vi.mocked(listSessionProfiles).mockResolvedValue({ items: [] }) }) it('renders dynamic fields and submits startTask with consent', async () => { @@ -108,6 +116,7 @@ describe('ToolConfig dynamic schema flow', () => { }), true, 'quick', + expect.any(Object), ) }) }) diff --git a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx index 4c0b2213..6a9b0bdc 100644 --- a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { MemoryRouter, Route, Routes } from 'react-router-dom' import ToolConfig from '../../../src/pages/ToolConfig' -import { getPluginSchema, listPlugins, startTask, getSettings } from '../../../src/api' +import { getPluginSchema, listPlugins, startTask, getSettings, listTargetPolicies, listCredentialProfiles, listSessionProfiles } from '../../../src/api' import { routes } from '../../../src/routes' const addToast = vi.fn() @@ -16,6 +16,9 @@ vi.mock('../../../src/api', () => ({ getPluginSchema: vi.fn(), startTask: vi.fn(), getSettings: vi.fn(), + listTargetPolicies: vi.fn(), + listCredentialProfiles: vi.fn(), + listSessionProfiles: vi.fn(), })) describe('ToolConfig timeout control', () => { @@ -60,6 +63,9 @@ describe('ToolConfig timeout control', () => { vi.mocked(getSettings).mockResolvedValue({ sandbox: { default_timeout: 600 } }) vi.mocked(startTask).mockResolvedValue({ task_id: 'task-1', status: 'queued', created_at: 'now', stream_url: '' }) + vi.mocked(listTargetPolicies).mockResolvedValue({ items: [] }) + vi.mocked(listCredentialProfiles).mockResolvedValue({ items: [] }) + vi.mocked(listSessionProfiles).mockResolvedValue({ items: [] }) }) it('renders integer input with constrained min/max', async () => { diff --git a/frontend/testing/unit/pages/Workflows.test.tsx b/frontend/testing/unit/pages/Workflows.test.tsx index 7c304da8..594ab4f8 100644 --- a/frontend/testing/unit/pages/Workflows.test.tsx +++ b/frontend/testing/unit/pages/Workflows.test.tsx @@ -130,7 +130,7 @@ describe('Workflows — create action', () => { name: 'Nightly Scan', schedule_seconds: 7200, enabled: true, - steps: [{ plugin_id: '', inputs: {} }], + steps: [{ plugin_id: '', inputs: {}, execution_context: { scan_profile: 'standard', validation_mode: 'proof', evidence_level: 'standard' } }], }) }) }) From aff2f9b35ba4e3f4c60559873bf374576e1928b8 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 6 Jun 2026 13:27:37 +0530 Subject: [PATCH 2/2] fix(ts): add total field to NamedResourceList mocks for TypeScript compliance { items: [] } was inferred as { items: never[] }, which does not satisfy NamedResourceList (requires items: T[] and total: number). Added total: 0 to all three mock returns so TypeScript accepts the fixture without casting. --- frontend/testing/unit/pages/ToolConfigDynamic.test.tsx | 6 +++--- frontend/testing/unit/pages/ToolConfigTimeout.test.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx index 9b53b37b..9aa5c6eb 100644 --- a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx @@ -79,9 +79,9 @@ describe('ToolConfig dynamic schema flow', () => { stream_url: '/api/v1/task/task-123/stream', }) vi.mocked(getSettings).mockResolvedValue(null) - vi.mocked(listTargetPolicies).mockResolvedValue({ items: [] }) - vi.mocked(listCredentialProfiles).mockResolvedValue({ items: [] }) - vi.mocked(listSessionProfiles).mockResolvedValue({ items: [] }) + vi.mocked(listTargetPolicies).mockResolvedValue({ items: [], total: 0 }) + vi.mocked(listCredentialProfiles).mockResolvedValue({ items: [], total: 0 }) + vi.mocked(listSessionProfiles).mockResolvedValue({ items: [], total: 0 }) }) it('renders dynamic fields and submits startTask with consent', async () => { diff --git a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx index 6a9b0bdc..44ef9b4d 100644 --- a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx @@ -63,9 +63,9 @@ describe('ToolConfig timeout control', () => { vi.mocked(getSettings).mockResolvedValue({ sandbox: { default_timeout: 600 } }) vi.mocked(startTask).mockResolvedValue({ task_id: 'task-1', status: 'queued', created_at: 'now', stream_url: '' }) - vi.mocked(listTargetPolicies).mockResolvedValue({ items: [] }) - vi.mocked(listCredentialProfiles).mockResolvedValue({ items: [] }) - vi.mocked(listSessionProfiles).mockResolvedValue({ items: [] }) + vi.mocked(listTargetPolicies).mockResolvedValue({ items: [], total: 0 }) + vi.mocked(listCredentialProfiles).mockResolvedValue({ items: [], total: 0 }) + vi.mocked(listSessionProfiles).mockResolvedValue({ items: [], total: 0 }) }) it('renders integer input with constrained min/max', async () => {