Skip to content

fix(security): make scan report latency independent of scan history (MCP-2205)#655

Merged
Dumbris merged 2 commits into
mainfrom
fix/mcp-2205-scan-report-latency
Jun 14, 2026
Merged

fix(security): make scan report latency independent of scan history (MCP-2205)#655
Dumbris merged 2 commits into
mainfrom
fix/mcp-2205-scan-report-latency

Conversation

@Dumbris

@Dumbris Dumbris commented Jun 14, 2026

Copy link
Copy Markdown
Member

Problem (MCP-2205)

Opening a security scan report is slow and gets slower the more a server is scanned. Reported by Algis: GET /api/v1/security/scans/{id}/report measured 2.0s cold / 0.7s warm for a tiny 13.8KB payload (5 scanner statuses, small stdout/stderr) on com.pulsemcp/google-flights (50 jobs accrued Apr 10 → Jun 14).

Root cause

GetScanReportByJobID (and the latest-report path via findLatestPassJobs) resolved companion/latest Pass-1/Pass-2 jobs with storage.ListScanJobs(serverName), which deserializes every scan job for the server. Each ScanJob carries large scanner stdout/stderr in ScannerStatuses, so cold latency is dominated by reading/deserializing the entire scan history — cost grows with how often the server has been scanned, not with the report being viewed.

Fix (option (a) from the issue — index by job/started_at)

  • New lightweight persisted index security_scan_job_index storing ScanJobMeta (id, server, status, scan_pass, started/completed) — no stdout/stderr.
  • Maintained transactionally on SaveScanJob / DeleteScanJob / DeleteServerScanJobs, and backfilled on DB open for databases created before the index (idempotent: only runs when the index is empty but jobs exist).
  • GetScanReportByJobID resolves the companion Pass-2 job via the index (findCompanionPass2JobID) and fetches only that one job's reports.
  • findLatestPassJobs resolves the newest Pass-1/Pass-2 via the index and then does at most two targeted GetScanJob loads.

Report latency is now independent of scan-output size and history depth. Report contents are unchanged.

Tests (TDD)

  • internal/security/scanner: deterministic guards that both report hot paths perform zero full-history ListScanJobs calls even with 100+ historical jobs, while still merging companion Pass-2 findings correctly.
  • internal/storage: ListScanJobMetas projection + server filtering, index maintenance on delete/delete-server, and backfill from a pre-index database.
  • Updated the spec-047 GetScanSummary negative-cache tests to track the lightweight probe (ListScanJobMetas) the code now uses; the caching contract is unchanged.

Verification

  • go test ./internal/security/scanner/ ./internal/storage/ — pass (incl. -race)
  • ./scripts/run-linter.sh — 0 issues
  • go build ./... (personal), go build -tags server ./internal/storage/... ./internal/security/..., go vet — clean

Note: the pre-existing internal/teams/broker server-edition build break (undefined: CredentialStore) is present on origin/main and unrelated to this change.

Related MCP-2205

…MCP-2205)

GetScanReportByJobID and the latest-report path resolved companion/latest
Pass-1/Pass-2 jobs via storage.ListScanJobs(serverName), which deserializes
every scan job for the server — each carrying large scanner stdout/stderr in
ScannerStatuses. Cold report latency therefore grew with a server's scan
history (measured ~2.0s cold for a 13.8KB report on a server with 50 jobs).

Introduce a lightweight persisted ScanJobMeta index (security_scan_job_index
bucket), maintained on SaveScanJob/DeleteScanJob/DeleteServerScanJobs and
backfilled on open for pre-existing databases. Companion and latest-job lookups
now read this index (small fixed-size records, no stdout/stderr) and fetch only
the one or two full jobs actually needed, so report latency no longer scales
with scan-output size or history depth.

Deterministic tests assert the report hot paths never invoke the full-history
ListScanJobs, plus storage-level coverage for the index (projection, filtering,
delete maintenance, and backfill).
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 14, 2026

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: aa7d4c8
Status: ✅  Deploy successful!
Preview URL: https://185de16a.mcpproxy-docs.pages.dev
Branch Preview URL: https://fix-mcp-2205-scan-report-lat.mcpproxy-docs.pages.dev

View logs

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown

📦 Build Artifacts

Workflow Run: View Run
Branch: fix/mcp-2205-scan-report-latency

Available Artifacts

  • archive-darwin-amd64 (28 MB)
  • archive-darwin-arm64 (25 MB)
  • archive-linux-amd64 (16 MB)
  • archive-linux-arm64 (14 MB)
  • archive-windows-amd64 (28 MB)
  • archive-windows-arm64 (24 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (21 MB)
  • installer-dmg-darwin-arm64 (19 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 27487929829 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 66.11570% with 41 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/storage/scanner.go 68.75% 10 Missing and 10 partials ⚠️
internal/security/scanner/service.go 70.00% 9 Missing and 6 partials ⚠️
internal/storage/manager.go 0.00% 4 Missing ⚠️
internal/storage/bbolt.go 33.33% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@mcpproxy-gatekeeper mcpproxy-gatekeeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Claude Code review (Codex quota exhausted). Reviewed diff + ran tests; verdict ACCEPT. See review notes.

@Dumbris Dumbris merged commit 2185e5c into main Jun 14, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants