fix(scanner): wire ramparts v0.8.x URL/stdio scanning via static replay shim#670
Conversation
…ay shim Ramparts v0.8.x dropped file/directory scanning: `ramparts scan <target>` now requires a live MCP endpoint (URL or `stdio:`), and `scan`'s --format no longer accepts `sarif` nor a `--output` flag. The container's entrypoint still ran the stale `--format sarif --output FILE /scan/source`, so every scan failed even after the image was unblocked (MCP-2395/#665). Bridge the source-tree model to the new endpoint model without ever executing the untrusted upstream (preserves the no-exec invariant, MCP-2206/#658): - mcp-replay.py: a static MCP stdio server that replays the tool definitions MCPProxy already exports into /scan/source/tools.json (the same file the Cisco scanner consumes). entrypoint runs `ramparts scan stdio:python3:.../mcp-replay.py --format json`. Unit-tested against the rmcp handshake (initialize/tools-list/ resources/prompts/ping/notifications/unknown-method/missing-file). - Dockerfile: pin ramparts 0.8.2, ship its YARA `rules/`, `taxonomies/` and `config.yaml` (loaded relative to CWD — a binary-only image loads zero rules and finds nothing), and add a python3 runtime for the shim. - engine.go: the rampartsIssue parser was also stale — v0.8.x serializes `issue_type`/`severity`/`message`/`details` (+ per-kind subject), not the old `type`/`impact`, so security_issues parsed with empty rule IDs and wrong severities. Updated to the v0.8.x shape; the yara_results path was already compatible. Parser proven end-to-end with a faithful v0.8.2 `--format json` fixture. - registry: NetworkReq false (replay shim is local, YARA offline); refreshed description/comments. - docs: refresh the ramparts design + the now-fixed/amd64-only arm64 note. Full container E2E (built amd64 image vs a poisoned server) runs in CI/QA. Related MCP-2422
Deploying mcpproxy-docs with
|
| Latest commit: |
e1612e6
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8dfb0cf3.mcpproxy-docs.pages.dev |
| Branch Preview URL: | https://fix-ramparts-v08-url-scannin.mcpproxy-docs.pages.dev |
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
📦 Build ArtifactsWorkflow Run: View Run Available Artifacts
How to DownloadOption 1: GitHub Web UI (easiest)
Option 2: GitHub CLI gh run download 27505356721 --repo smart-mcp-proxy/mcpproxy-go
|
There was a problem hiding this comment.
Claude review ACCEPT — ramparts v0.8.x URL/stdio scanning via static replay shim. Verified: correct v0.8.x CLI invocation, no-exec invariant (shim re-serves tools.json, never re-executes upstream), tools.json data contract (inputSchema), output parsing (issue_type/severity/message), report pickup (results.json), tests green, no regression to other scanners. Residual full-container E2E deferred to QA.
Apply four hardenings to the npx/uvx package-source fetch extractor (internal/security/scanner/package_fetch.go), for both the tar and zip paths, while keeping behavior identical for well-formed small archives: 1. Decompression bomb across skipped members: read the gzip tar stream through a cappedReader so EVERY decompressed byte is bounded — including the bodies of members the extractor skips (oversized, symlink, traversal), which tar.Reader still decompresses while advancing to the next header. 2. safeJoin REJECTS path-traversal and absolute entries with an error instead of cleaning '../' into an in-dest path (the rewrite bug). 3. Oversized and partially-written files are charged to the file-count and byte caps (a truncated-but-large file still counts). 4. Directory creation is capped (charged to the same combined entry limit) before the file-count limit can be bypassed by an all-directories archive — for both tar and zip. extractTarballGz/extractZip take an explicit maxFileBytes so the per-file cap is testable. Adds TDD fixtures: gzip bomb of skipped members, traversal reject (not rewrite), oversized-charged, dir cap. Related #670
Problem (MCP-2422)
Ramparts v0.8.x dropped file/directory scanning.
ramparts scan <target>now requires a live MCP endpoint (HTTP URL orstdio:subprocess),scan's--formatno longer acceptssarif, and there is no--outputflag. The container entrypoint still ran the stale--format sarif --output FILE /scan/source, so every ramparts scan failed even after the image build was unblocked (MCP-2395/#665). Two further latent breaks surfaced during the fix:rules/(andtaxonomies/,config.yaml) from the working directory at runtime, so even a corrected CLI would load zero rules → no findings.rampartsIssueparser was also stale: v0.8.x serializesissue_type/severity/message/details(+ per-kind subject), not the oldtype/impact, sosecurity_issuesparsed with empty rule IDs and mis-graded severities.Approach — static stdio replay shim (no untrusted execution)
MCPProxy must never re-execute the untrusted upstream just to give ramparts a target (would violate the no-exec invariant, MCP-2206/#658). Instead the engine already exports the captured tool definitions into
/scan/source/tools.json(the file the Cisco scanner consumes). We replay them:mcp-replay.pyspeaks just enough MCP stdio (initialize → tools/list → resources/prompts → ping) to serve those static definitions. No upstream code runs.Changes
docker/scanners/ramparts/mcp-replay.py(+mcp-replay_test.py, 6/6 passing) — static MCP stdio replay server.entrypoint.sh— v0.8.x invocation; emit native JSON, tolerate findings/offline-LLM non-zero exit, fail only if no report.Dockerfile— pin ramparts0.8.2, shiprules/+taxonomies/+config.yaml, addpython3.engine.go— fixrampartsIssueto the v0.8.xSecurityIssueshape (yara_results path was already compatible).registry_bundled.go—NetworkReq: false(shim is local, YARA offline); refreshed description/comments.amd64-only / emulated-on-arm64 status.Verification
go build ./...✅go test ./internal/security/... -race✅ (incl. newTestEngineParseResultsRampartsV08JSONproving the exact v0.8.2--format jsonshape yields findings, andTestRampartsV08Invariants)python3 docker/scanners/ramparts/mcp-replay_test.py→ 6/6 ✅golangci-lint(v2, CI config) → 0 issues ✅;shellcheck entrypoint.sh✅;gofmtclean ✅Deferred to CI/QA: full container E2E (built
amd64image vs a poisoned MCP server). No Rust toolchain locally and the image is amd64-only, so the end-to-end "findings out of the built image" check runs in CI + QA. The parse-boundary and shim-protocol layers are unit-proven here.Related MCP-2422