Skip to content

fix: comfy generate refresh fetches /openapi with /openapi.yml fallback (BE-3391)#560

Open
mattmillerai wants to merge 1 commit into
mainfrom
matt/be-3391-generate-refresh-openapi
Open

fix: comfy generate refresh fetches /openapi with /openapi.yml fallback (BE-3391)#560
mattmillerai wants to merge 1 commit into
mainfrom
matt/be-3391-generate-refresh-openapi

Conversation

@mattmillerai

Copy link
Copy Markdown
Collaborator

ELI-5

comfy generate refresh downloads the latest list of partner AI models so the CLI knows about brand-new ones. It was asking the server for a file at /openapi.yml — but that address now returns 404 Not Found. The real, up-to-date spec lives at /openapi (no extension, served as JSON). So refresh — the only way to update the model catalog — was completely broken. This points it at the working address (and keeps the old one as a fallback), and refuses to save anything that isn't a real spec so a bad download can't silently break comfy generate for the next 7 days.

What changed

  • _refresh() (app.py) now fetches spec.base_url() + "/openapi" first, and falls back to /openapi.yml on a 404 — preserving any custom COMFY_API_BASE_URL deployment that still serves the .yml path.
  • Validate before caching: the fetched body is parsed with the same loader spec.load_raw_spec() uses (validate_spec_text(), new helper in spec.py) and must contain a top-level paths mapping. JSON is a subset of YAML 1.2 and the custom loader only restricts bool resolution, so the JSON body served at /openapi parses cleanly. If the body doesn't parse or has no paths, refresh exits 1 without writing the cache — previously a 200-with-garbage response would have been cached into ~/.comfy/openapi-cache.yml and poisoned every subsequent comfy generate for CACHE_TTL_SECONDS (7 days).
  • spec.write_cache() is unchanged — the cache file staying .yml is fine since the loader reads JSON.

Verification

  • End-to-end against the real api.comfy.org (the acceptance criterion):
    • comfy generate refresh → fetched /openapi (HTTP 200, ~973 KB JSON), wrote ~/.comfy/openapi-cache.yml, printed Refreshed model catalog.
    • comfy generate list afterwards read the refreshed cache and rendered the model table (including flux-2, which is ahead of the vendored spec/openapi.yml).
    • Confirmed the old path is dead: curl -so /dev/null -w '%{http_code}' https://api.comfy.org/openapi.yml404; /openapi200 application/json.
  • Unit tests (tests/comfy_cli/command/generate/):
    • (a) refresh hits /openapi and writes the cache on a valid JSON spec body;
    • (b) a 404 on /openapi falls back to /openapi.yml;
    • (c) an invalid body (non-parse or 200-with-no-paths) exits 1 and leaves a pre-existing cache byte-for-byte untouched;
    • (d) a cached JSON body round-trips through spec.load_raw_spec() and spec.get_endpoint() resolves an endpoint from it.
  • ruff format --check + ruff check clean on the changed files; full suite green (2573 passed, 37 skipped).

Notes / judgment calls

  • Chesterton's fence — changing the fetch URL is intentional, not a silent regression. The old default (/openapi.yml) is empirically 404 today; the change is authorized by the ticket and the old path is retained as a 404 fallback, so custom deployments serving the .yml path keep working.
  • Test isolation: added an autouse _isolate_spec_caches fixture to test_app.py that clears the module-level load_raw_spec / _registry lru_caches around each test. The new refresh tests monkeypatch spec._USER_CACHE to a temp file, and base_url() loads that temp spec into the process-global caches; without the clear, a temp spec leaked into later tests (empty registry → spurious "No models match" failures). The fixture adds a small re-parse cost per test but keeps the suite deterministic.

…ck (BE-3391)

api.comfy.org/openapi.yml returns 404; the live spec is served at
/openapi (JSON body). _refresh() now fetches /openapi first and falls
back to /openapi.yml on a 404 (preserving custom COMFY_API_BASE_URL
deployments that serve the yml path). Validate the fetched body with the
same loader load_raw_spec uses and require a top-level 'paths' mapping
before caching, so a 200-with-garbage response can no longer poison
~/.comfy/openapi-cache.yml for the 7-day TTL.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. bug Something isn't working labels Jul 18, 2026
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e1fc3dba-8ea5-4f43-87e6-7f32280a4567

📥 Commits

Reviewing files that changed from the base of the PR and between a732f5c and 7e84869.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • comfy_cli/command/generate/app.py
  • comfy_cli/command/generate/spec.py
  • tests/comfy_cli/command/generate/test_app.py
  • tests/comfy_cli/command/generate/test_spec.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3391-generate-refresh-openapi
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-3391-generate-refresh-openapi

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

@mattmillerai mattmillerai added agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review labels Jul 18, 2026

@github-actions github-actions 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.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

⚠️ Review failed

Judge call failed (status=parse_error): Could not parse JSON findings from output. First 500 chars:
Based on my review of the actual code, I've verified each finding. Key checks: `_YamlLoader` **does** inherit from `yaml.SafeLoader` (spec.py:24), so Gemini's RCE claim is a false positive — I've dropped that and kept only the real YAML-bomb DoS. `base_url()` (spec.py:280-286) reads `servers[0]["url"]` from the cached spec and is called outside `_refresh`'s try block; `_registry()` (spec.py:339) does `next(iter(node.keys()))` which crashes on string path values. All confirmed.

[
  {
    "file":

Re-trigger by removing and re-adding the cursor-review label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-coded PR authored by the agent-work loop bug Something isn't working cursor-review Request Cursor bot review size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant