Skip to content

refactor(http): shared is_cloud-gated target_auth_headers builder; migrate 5 call sites (BE-4362) - #597

Open
mattmillerai wants to merge 2 commits into
mainfrom
matt/be-4362-shared-auth-header-builder
Open

refactor(http): shared is_cloud-gated target_auth_headers builder; migrate 5 call sites (BE-4362)#597
mattmillerai wants to merge 2 commits into
mainfrom
matt/be-4362-shared-auth-header-builder

Conversation

@mattmillerai

Copy link
Copy Markdown
Collaborator

ELI-5

Five different places in the code each wrote their own little "attach the login token to this request" snippet. They'd drifted: three of them attached the token to any target — even a plain-HTTP local ComfyUI — instead of only to Comfy Cloud. This PR replaces all five copies with one shared helper, target_auth_headers(target), that attaches credentials only when target.is_cloud. Same behavior in practice today (local targets are built with no credentials), but a stray token on a local target can now never leak to a plaintext server.

What changed

Adds target_auth_headers(target) -> dict[str, str] to comfy_cli/http.py — the strictest variant (promoted verbatim from transfer._auth_headers): it returns {} unless target.is_cloud, then X-API-Key (api_key) taking precedence over Authorization: Bearer (auth_token). This is the same defense-in-depth gate comfy_client.Client already uses.

Migrated the five hand-rolled non-client copies onto it:

Site Change
command/workflow.py _authed_request lazy import + header loop (was ungated — now gated)
command/models/search.py _authed_request lazy import + header loop (was ungated — now gated)
command/jobs.py _cloud_cancel (inline) lazy import + header loop (was ungated — now gated)
command/transfer.py _auth_headers deleted body, re-exported: from comfy_cli.http import target_auth_headers as _auth_headers (was already gated — byte-identical)
cql/engine.py _load_from_target (inline) header loop (was already gated, api_key-first — byte-identical)

Left untouched by design: comfy_client.py:264-268 (superset path with safe-URL assertion + 401 refresh-retry), and every HTTPError→envelope mapper / capped-reader (a separate follow-up ticket). Non-Target header sites (generate/client.py's bare-api_key builder, GitHub/Civitai token headers in install.py/models.py) are out of scope — they don't route a Target.

Security note

The gate direction is the point: attach nothing unless target.is_cloud. The three previously-ungated sites (workflow/search/jobs) attached credentials whenever they were present, regardless of target kind. Behavior is preserved today because resolve_target builds local Targets with auth_token=None and no api_key (target.py:118-127), so no observable change — but the latent leak path (a stray credential on a local target → plaintext server) is now closed. This also means local /userdata calls in workflow.py go from "attach if creds present" to "never attach," which _userdata_request's docstring already described as a no-op.

Tests

  • Added 4 cases to tests/comfy_cli/test_http.py, including the security property: a local Target with both auth_token and api_key set → target_auth_headers returns {}; plus cloud api-key-only, cloud auth-token-only, and cloud-both (api_key wins).
  • Full existing suites for all migrated commands pass unchanged: test_workflow_saved.py, models/test_search.py, jobs/test_jobs.py, test_transfer_{download,redirect,upload}.py, and the cql/ suite (135 passed + 248 passed, 1 skipped). Their target fixtures are cloud-kind, so headers still attach.
  • ruff check + ruff format --check clean on all touched files.

Phase 1 of BE-4350.

…grate 5 call sites (BE-4362)

Converge the five hand-rolled non-client copies of the Target auth-header
policy onto one shared, strictest-variant builder in comfy_cli/http.py.

The gate direction is security-sensitive: attach NOTHING unless
target.is_cloud. This is behavior-preserving today (local Targets are
constructed with no credentials) while closing the latent path where a
stray credential on a local target would be sent to a plaintext server by
the previously-ungated workflow/search/jobs sites.

Migrated: workflow._authed_request, models/search._authed_request,
jobs._cloud_cancel (inline), transfer._auth_headers (re-export), and
cql/engine._load_from_target (inline). comfy_client.py's superset path
(safe-URL assertion + 401 refresh-retry) is intentionally left as-is.
@mattmillerai mattmillerai added cursor-review Request Cursor bot review agent-coded PR authored by the agent-work loop labels Jul 24, 2026
@mattmillerai
mattmillerai marked this pull request as ready for review July 24, 2026 09:55
@coderabbitai

coderabbitai Bot commented Jul 24, 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: 34 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: 4c02985f-451f-47ae-9fd4-cc38090f5dab

📥 Commits

Reviewing files that changed from the base of the PR and between 6c88dd7 and 3812b13.

📒 Files selected for processing (7)
  • comfy_cli/command/jobs.py
  • comfy_cli/command/models/search.py
  • comfy_cli/command/transfer.py
  • comfy_cli/command/workflow.py
  • comfy_cli/cql/engine.py
  • comfy_cli/http.py
  • tests/comfy_cli/test_http.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-4362-shared-auth-header-builder
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-4362-shared-auth-header-builder

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

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jul 24, 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.

✅ No high-signal findings.

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

@skishore23 skishore23 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — land before #530

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 28, 2026
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 cursor-review Request Cursor bot review lgtm This PR has been approved by a maintainer size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants