Skip to content

fix: P1 quick-win findings from comprehensive review#28

Merged
hybridindie merged 3 commits intofix/critical-security-findingsfrom
fix/p1-quick-wins
Mar 12, 2026
Merged

fix: P1 quick-win findings from comprehensive review#28
hybridindie merged 3 commits intofix/critical-security-findingsfrom
fix/p1-quick-wins

Conversation

@hybridindie
Copy link
Owner

Summary

Addresses 9 high-priority quick-win findings from the comprehensive code review (P1 items that are small effort):

Based on: PR #27 (P0 critical security fixes)

Test plan

  • All 359 tests pass (8 new tests)
  • ruff check clean
  • ruff format --check clean
  • mypy clean
  • All pre-commit hooks pass
  • Verify CI passes on GitHub

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 12, 2026 23:04
fix: address all critical (P0) security findings
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a set of P1 “quick-win” items from a comprehensive review, spanning Model Manager availability caching, path-injection test coverage, integration-test correctness, CI gating for Docker publishes, Docker compose volume paths for a non-root container, and targeted security/ops documentation updates.

Changes:

  • Add an expiring negative cache (5 min TTL) for ComfyUI-Model-Manager detection and cover it with a regression test.
  • Add new path-injection prevention tests and refactor integration tests to use register_*_tools() return dicts rather than private SDK internals.
  • Gate Docker image publishing on a new CI test job; update Docker compose mounts for the non-root runtime; expand README security/ops guidance and remove a duplicate threat-model row.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/comfyui_mcp/model_manager.py Adds negative-cache TTL logic for Model Manager detection so late-starting plugins can be detected without restart.
tests/test_model_manager.py Adds a regression test verifying negative cache expiry and re-probing behavior.
tests/test_client.py Adds tests validating prompt_id/path-segment validation and HTTP method allowlisting.
tests/test_integration.py Refactors integration tests to call functions returned by register_*_tools() instead of private _tool_manager._tools.
docker-compose.yml Updates bind/volume mount locations to /home/app/... to align with non-root container usage.
README.md Adds SSE unauthenticated exposure warning, audit vs enforce guidance, log rotation example, and removes a duplicated threat-model row.
.github/workflows/docker.yml Adds a test job (lint/typecheck/pytest) and makes the Docker publish job depend on it.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +10 to +11
- ./config.yaml:/home/app/.comfyui-mcp/config.yaml:ro
- comfyui-mcp-data:/home/app/.comfyui-mcp/logs
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The docker-compose volume mounts were switched to /home/app/.comfyui-mcp/..., but the image’s app user currently appears to be created without a home directory (see Dockerfile useradd --system), so Path.home()/~ may resolve to /nonexistent and /home/app may not exist or be writable. This can cause the server to ignore the mounted config.yaml and/or fail to write logs. Consider either creating /home/app for the app user in the image (and setting HOME), or update the compose mounts to match the actual runtime home/config paths used by the container.

Suggested change
- ./config.yaml:/home/app/.comfyui-mcp/config.yaml:ro
- comfyui-mcp-data:/home/app/.comfyui-mcp/logs
- ./config.yaml:/nonexistent/.comfyui-mcp/config.yaml:ro
- comfyui-mcp-data:/nonexistent/.comfyui-mcp/logs

Copilot uses AI. Check for mistakes.
Comment on lines +232 to +235
async def test_prompt_id_valid_uuid_accepted(self, client):
# Should not raise ValueError (will fail on HTTP, but that's fine)
with pytest.raises(httpx.ConnectError):
await client.get_history_item("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

test_prompt_id_valid_uuid_accepted makes a real HTTP call (no respx.mock) and asserts on httpx.ConnectError. Because the client retries with backoff, this can be slow and potentially flaky depending on DNS/network behavior in CI. Prefer mocking the /history/{prompt_id} route with respx (and asserting the request was made) so the test stays deterministic while still verifying that UUID-shaped prompt_ids are accepted by the validator.

Suggested change
async def test_prompt_id_valid_uuid_accepted(self, client):
# Should not raise ValueError (will fail on HTTP, but that's fine)
with pytest.raises(httpx.ConnectError):
await client.get_history_item("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
@respx.mock
async def test_prompt_id_valid_uuid_accepted(self, client):
# Valid UUID-shaped prompt_id should be accepted by the validator
route = respx.get(
"http://test-comfyui:8188/history/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
).mock(
return_value=httpx.Response(
200,
json={"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee": {"outputs": {}}},
)
)
result = await client.get_history_item("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
assert "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" in result
assert route.call_count == 1

Copilot uses AI. Check for mistakes.
await detector.validate_folder("invalid_folder")

@respx.mock
async def test_negative_cache_expires(self, client, monkeypatch):
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The monkeypatch fixture is included in this test signature but never used. Please remove it to keep the test minimal and avoid suggesting that time or environment is being patched when it isn’t.

Suggested change
async def test_negative_cache_expires(self, client, monkeypatch):
async def test_negative_cache_expires(self, client):

Copilot uses AI. Check for mistakes.
John D and others added 2 commits March 12, 2026 19:13
- Add negative TTL (5 min) to ModelManagerDetector so a late-starting
  Model Manager is detected without requiring server restart (#13)
- Add path injection prevention tests for prompt_id, node_class,
  task_id, and HTTP method validation (#19)
- Rewrite integration tests to use register_*_tools() return dicts
  instead of accessing private _tool_manager._tools SDK attrs (#20)
- Gate Docker image push on test/lint job success via needs: (#22)
- Fix docker-compose volume paths for non-root container user (#23)
- Document SSE transport security risks with warning callout (#24)
- Add audit vs enforce mode operational guidance table (#25)
- Add audit log rotation docs with logrotate example (#26)
- Remove duplicate row in threat model table (#52)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dockerfile: use --create-home so /home/app exists for config/log mounts
- test_client: mock valid UUID test with respx instead of real HTTP call
- test_model_manager: remove unused monkeypatch parameter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@hybridindie hybridindie merged commit c441b1c into fix/critical-security-findings Mar 12, 2026
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