Skip to content

fix: harden serve/web/CLI/i18n from repo-health findings (#105, #96, #102, #99, #106) - #108

Merged
Liohtml merged 2 commits into
mainfrom
claude/repo-issues-features-3ZLdb
Jun 16, 2026
Merged

fix: harden serve/web/CLI/i18n from repo-health findings (#105, #96, #102, #99, #106)#108
Liohtml merged 2 commits into
mainfrom
claude/repo-issues-features-3ZLdb

Conversation

@Liohtml

@Liohtml Liohtml commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Bundles five clearly-scoped fixes from the latest repo-health-agent batch. Each is low-risk, self-contained, and ships with a regression test.

Changes

# Sev Fix
#105 High serve now honours MEDCHECK_HOST / MEDCHECK_PORT via Typer envvar=. The Docker image sets ENV MEDCHECK_HOST=0.0.0.0 and runs medcheck serve with no --host, but the hardcoded 127.0.0.1 default meant the container bound to loopback and was unreachable from the host. Now the env vars take effect when the flag is omitted.
#96 Medium POST /api/analyze returns 501 Not Implemented instead of 200 OK for the not-yet-wired stub, so clients, health checks, and CI can detect that no analysis ran.
#102 Medium load_anatomy_instructions uses @lru_cache(maxsize=64) instead of unbounded @cache. The /api/analyze body can supply arbitrary anatomy strings; an unbounded cache grows without limit.
#99 Low analyze validates --report / --lang and fails fast with a clear error instead of silently falling through to a JSON report on e.g. --report xml.
#106 Low i18n _load_catalog() confines lang to a safe pattern before building a file path (defense-in-depth: the loader is reachable from the CLI with an unvalidated --lang).

Tests

  • test_serve_honors_host_port_env — patches uvicorn.run, asserts host/port come from env
  • test_analyze_open_when_no_api_key_configured / test_analyze_requires_key_when_configured — updated to expect 501
  • test_analyze_rejects_invalid_report_format / test_analyze_rejects_invalid_language
  • test_i18n_rejects_path_traversal_lang

Full suite (130 tests) + mypy --strict + ruff check/ruff format all green locally.

Not included (deliberately)

Closes #105, #96, #102, #99, #106


Generated by Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for additional languages (fr, es) via the --lang option and /api/analyze request schema.
    • serve now reads MEDCHECK_HOST and MEDCHECK_PORT environment variables when --host/--port aren’t provided.
  • Bug Fixes

    • POST /api/analyze now returns 501 Not Implemented (instead of a success response).
    • Hardened language handling to prevent path traversal issues in translations.
    • Improved memory safety by capping cached anatomy instructions.

- serve: read MEDCHECK_HOST/MEDCHECK_PORT via Typer envvar so the Docker
  image's ENV MEDCHECK_HOST=0.0.0.0 takes effect (container was unreachable) (#105)
- web: POST /api/analyze returns 501 (not 200) for the unimplemented stub
  so clients/health checks can detect it (#96)
- vision_analysis: bound load_anatomy_instructions cache with lru_cache(maxsize=64)
  instead of unbounded @cache to cap memory from request-supplied anatomy (#102)
- cli: validate --report and --lang, failing fast on unknown values instead of
  silently defaulting to JSON (#99)
- i18n: confine _load_catalog lang to a safe pattern before building a path
  (defense-in-depth against traversal via unvalidated --lang) (#106)

Adds regression tests for each. Full suite + mypy + ruff green.

https://claude.ai/code/session_01KYcUxCGAHaTPrRHTzJCWQz
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bd5652e5-f81c-4715-8c46-5889fa5a6983

📥 Commits

Reviewing files that changed from the base of the PR and between 60c21be and 899cdbc.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/medcheck/web/app.py
  • tests/unit/test_web.py
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

The PR hardens the medcheck application across four areas: i18n language codes are validated with a regex before file path construction to prevent traversal; the analyze CLI command fails fast on unknown --report/--lang values via a new _validate_choice helper; the serve command reads MEDCHECK_HOST/MEDCHECK_PORT from environment variables; load_anatomy_instructions uses a bounded lru_cache(maxsize=64) instead of unbounded @cache; and the /api/analyze stub returns HTTP 501 instead of 200, with expanded language support from en, de to en, de, fr, es.

Changes

Security, Validation, and Stub Corrections

Layer / File(s) Summary
i18n language code validation and path-traversal guard
src/medcheck/i18n/loader.py, tests/unit/test_i18n.py, CHANGELOG.md
_LANG_RE regex is added and validated inside _load_catalog; invalid or traversal-like lang inputs return an empty catalog, falling back to English. A new test confirms path-traversal input (../../../../etc/passwd) does not leak outside the i18n directory. Security note added to changelog.
CLI fail-fast validation for --report and --lang options
src/medcheck/main.py, tests/unit/test_cli.py, CHANGELOG.md
Introduces _ALLOWED_FORMATS, _ALLOWED_LANGS, and _validate_choice helper; analyze normalizes and rejects unrecognized --report/--lang values before proceeding. Help text for --lang expanded to document en, de, fr, es. Three tests verify rejection of invalid values and proper error messages.
Serve environment variables and bounded anatomy cache
src/medcheck/main.py, src/medcheck/pipeline/vision_analysis.py, tests/unit/test_cli.py, CHANGELOG.md
Updates serve command to read MEDCHECK_HOST and MEDCHECK_PORT from environment variables when no explicit flags are provided. Changes load_anatomy_instructions from unbounded @cache to bounded @lru_cache(maxsize=64) with explanatory comment about capping memory growth. Test verifies env-var pickup for host and port. Changed items documented in changelog.
/api/analyze HTTP 501 stub and expanded language support
src/medcheck/web/app.py, tests/unit/test_web.py
Expands AnalyzeRequest.language validation regex from ^(en|de)$ to ^(en|de|fr|es)$. Changes /api/analyze POST handler to raise HTTPException(501) with a detail string, replacing the previous 200 JSON response. Tests verify 501 response in both open and authenticated modes, and validate that all four supported languages are accepted while unsupported languages are rejected with 422.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • Liohtml/MedCheck#102: The PR addresses the unbounded functools.cache memory growth problem by replacing @cache with @lru_cache(maxsize=64) on the load_anatomy_instructions function in src/medcheck/pipeline/vision_analysis.py.

Possibly related PRs

  • Liohtml/MedCheck#47: Both PRs modify the /api/analyze request/endpoint in src/medcheck/web/app.py by extending/using a validated AnalyzeRequest (including language handling), so the changes are directly connected in the same route/model.
  • Liohtml/MedCheck#6: Both PRs touch src/medcheck/main.py's serve --host option (one adds a security suppression, the other changes it to read MEDCHECK_HOST when unset), so the changes overlap at the same code location.
  • Liohtml/MedCheck#76: Both PRs touch the i18n layer—specifically src/medcheck/i18n/loader.py (language/catalog loading and English fallback behavior)—so this PR's added lang validation hardening is directly related to that PR's i18n catalog implementation.

Poem

🐇 A bunny checked the paths one day,
And found a traversal trying to stray.
With regex and cache kept trim and small,
The CLI now validates each call.
HTTP 501 stands proud and tall—
No sneaky lang code gets past the wall! 🔒

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: five targeted hardening fixes across serve/web/CLI/i18n modules, clearly referencing the associated issue numbers.
Description check ✅ Passed The description comprehensively documents all changes with a well-organized table, testing details, and explicit out-of-scope rationale; it meets the template requirements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/repo-issues-features-3ZLdb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/medcheck/web/app.py`:
- Around line 75-82: The AnalyzeRequest class is restricting the language field
to only en and de, which causes incoming requests with fr or es language codes
to fail validation with a 422 error before reaching the analyze endpoint
function. Update the language field validation in the AnalyzeRequest class to
include fr and es as supported values, ensuring requests with these newly
supported locales pass validation and reach the 501 stub endpoint rather than
being rejected during request parsing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ddd30cf9-b9a7-447e-870b-20c66a7dca24

📥 Commits

Reviewing files that changed from the base of the PR and between cce065f and 60c21be.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • src/medcheck/i18n/loader.py
  • src/medcheck/main.py
  • src/medcheck/pipeline/vision_analysis.py
  • src/medcheck/web/app.py
  • tests/unit/test_cli.py
  • tests/unit/test_i18n.py
  • tests/unit/test_web.py

Comment thread src/medcheck/web/app.py
The CLI now accepts en/de/fr/es and the i18n catalogs ship those locales, but
AnalyzeRequest restricted language to ^(en|de)$ — so fr/es requests were rejected
with 422 before reaching the endpoint. Align the schema pattern and add tests.

Addresses CodeRabbit review on #108.
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.

[repo-health] High: medcheck serve ignores MEDCHECK_HOST/MEDCHECK_PORT env vars — Docker deployment silently binds to 127.0.0.1 and is unreachable

2 participants