fix(generate): fetch spec from /openapi not /openapi.yml (BE-2982)#517
fix(generate): fetch spec from /openapi not /openapi.yml (BE-2982)#517mattmillerai wants to merge 3 commits into
Conversation
comfy-api serves the OpenAPI spec at /openapi (JSON, valid YAML); the old /openapi.yml path 404s, so `comfy generate refresh` always failed and exited 1. Point _refresh() at /openapi. The JSON body is written verbatim to the cache and parsed by load_raw_spec() with yaml.load (JSON is a YAML subset), so no further change is needed. Adds a regression test asserting _refresh() requests <base_url>/openapi.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe refresh command now fetches ChangesOpenAPI refresh validation
Sequence Diagram(s)sequenceDiagram
participant GenerateRefresh
participant OpenAPIEndpoint
participant validate_spec_text
participant OpenAPICache
GenerateRefresh->>OpenAPIEndpoint: GET /openapi
OpenAPIEndpoint-->>GenerateRefresh: Spec response text
GenerateRefresh->>validate_spec_text: Validate response text
validate_spec_text-->>GenerateRefresh: Parsed mapping or SpecError
GenerateRefresh->>OpenAPICache: Write valid response
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
There was a problem hiding this comment.
🔍 Cursor Review — Consolidated panel
Triggered by @mattmillerai.
Found 3 finding(s).
| Severity | Count |
|---|---|
| 🟠 High | 1 |
| 🟢 Low | 2 |
Panel: 6/8 reviewers contributed findings.
Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)
Harden the newly-activated `/openapi` refresh path per cursor-review: - Refuse to cache a non-spec 200. `_refresh()` follows redirects and caches the body verbatim for 7 days; an HTML interstitial / redirect landing page / JSON array or scalar would poison the cache and crash every `generate` subcommand (`.get()` on a non-mapping) until the TTL expired. Add `spec.validate_spec_text()` requiring a dict shaped like an OpenAPI doc, and gate `write_cache()` on it. - Parse JSON exponent floats. The remote serves JSON, where `json.dumps` emits point-less signed exponents (`1e+16`, `1e-07`) that PyYAML's YAML 1.1 float resolver treats as strings. Add a resolver for that form. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Automated resolver note: the only failing check ("Windows Specific Commands" / `test`) is a repo-wide infra flake, not caused by this PR. It fails in the Install Dependencies step (before any test runs) with: a Windows |
|
🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:
|
The `validate_spec_text()` guard and the point-less-exponent float resolver added in 633220f were verified by hand but had no regression test — either could be deleted with CI staying green. Add direct coverage in test_spec.py: - point-less exponents (`1e+16`, `1e-07`, `-2e+5`) resolve to float, which stock PyYAML's YAML 1.1 resolver leaves as str; - the resolver does not over-match version strings (`3.0.2`), the `on`/`off` string enums, or `v1e5`; - `validate_spec_text()` accepts an OpenAPI mapping and rejects an HTML interstitial, a JSON array, a bare scalar, and a non-OpenAPI mapping. Verified these fail against main's spec.py and pass with the fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Resolver pass — pushed 8613835 (test-only), no source changes needed. Review threads: all 3 were already addressed in 633220f (spec validation + JSON float resolver) and are resolved. The one deferral — origin-pinning (r3582325058) — is now recorded as a tracked follow-up rather than left in a reply; it needs a human call on whether Gap found and fixed: Verified the PR's premise empirically against the live API rather than trusting the description:
CI: the red No merge conflict — branch is 0 behind |
|
🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:
|
|
Resolver pass — no code changes needed; nothing in this diff is broken. Recording why the two red checks are not this PR.
Root cause: tomlkit 0.15.x now rejects newlines in comments, and Out of scope here (this PR is a one-line spec-fetch path fix in
This PR: all 3 review threads resolved and answered. No merge conflict ( |
|
Correction to my previous comment: the tomlkit 0.15
Those two overlapping fixes (#533/#536) probably want de-duplicating against each other, but that is a call for their authors, not this PR. Everything else in my previous comment stands: #517 needs no code changes — 3/3 review threads resolved, no merge conflict, |
ELI-5
comfy generate refreshdownloads the latest list of API models. It wasknocking on the wrong door —
/openapi.yml— which the server answers with"404 Not Found", so the command always failed and exited 1. The spec actually
lives at
/openapi(served as JSON). This changes the one URL so the dooropens.
What changed
comfy_cli/command/generate/app.py—_refresh()now fetches<base_url>/openapiinstead of<base_url>/openapi.yml._refresh()requests<base_url>/openapi.Nothing else needed changing: the server returns JSON, and JSON is a subset of
YAML, so
write_cache()(verbatim write) +load_raw_spec()(yaml.load)parse it fine.
base_url(), the vendored spec, and the/proxy/allowlist areuntouched.
Why it's safe
base_url()rstrips the trailing slash, so the URL resolves tohttps://api.comfy.org/openapi._refresh()is the only spec-fetch call site (grepped — all otheropenapi.ymlreferences are file paths: the bundled spec and the~/.comfy/openapi-cache.ymlcache filename).Verification (live, 2026-07-14)
GET https://api.comfy.org/openapi→ 200; body parses as YAML,openapi: 3.0.2,servers: [{url: https://api.comfy.org}](matches thevendored spec so
base_url()resolves identically), 314 paths.GET https://api.comfy.org/openapi.yml→ 404.ruff format --check+ruff checkclean.Notes
reading
base_url()after refresh repopulates thelru_cached spec fromthe freshly-written minimal tmp cache, which leaked into later tests. The
test now resolves the expected URL before invoking refresh.