Add deploy environment header (X-Comfy-Env) to partner node API calls#13425
Add deploy environment header (X-Comfy-Env) to partner node API calls#13425Kosinkadink wants to merge 2 commits intomasterfrom
Conversation
📝 WalkthroughWalkthroughAdds deployment-environment support: new module 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@comfy_api_nodes/util/client.py`:
- Around line 620-623: The X-Comfy-Env header is only being set inside the
"relative URL" branch, so absolute requests to the Comfy API host miss it;
update the logic so payload_headers["X-Comfy-Env"] is added whenever the request
targets the Comfy API host (either parsed_url has no scheme/netloc or
parsed_url.netloc matches cfg.endpoint.host or cfg.endpoint.netloc), not only
for relative URLs. Keep the existing get_auth_header(cfg.node_cls) behavior for
relative URLs but move or add the X-Comfy-Env assignment to run for both the
relative-URL branch and for absolute URLs whose netloc equals the configured
Comfy API endpoint (use parsed_url, payload_headers, cfg.endpoint to
locate/compare).
In `@comfy/deploy_environment.py`:
- Around line 21-25: The code reads env_file and caches its raw contents into
_cached_value which can contain newlines or control characters that will break
the X-Comfy-Env HTTP header; inside the with open(...) block (where env_file,
value and _cached_value are used) sanitize the value before caching by taking
only the first line (value.splitlines()[0] if any) and stripping it, then remove
any control/non-ASCII or non-printable characters (e.g. filter out chars with
ord() < 32 or ==127) so the resulting string is header-safe, and assign that
sanitized string to _cached_value before returning.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8f031b8d-8871-468e-a44f-985ac78a0163
📒 Files selected for processing (3)
.gitignorecomfy/deploy_environment.pycomfy_api_nodes/util/client.py
| if not parsed_url.scheme and not parsed_url.netloc: # is URL relative? | ||
| payload_headers.update(get_auth_header(cfg.node_cls)) | ||
| payload_headers["X-Comfy-Env"] = get_deploy_environment() | ||
| if cfg.endpoint.headers: |
There was a problem hiding this comment.
X-Comfy-Env is applied only for relative URLs, not all calls to the Comfy API host.
At Line 620, the new header is tied to the relative-URL branch. Absolute URLs to the same API host won’t carry X-Comfy-Env, so the environment signal is incomplete.
Suggested fix
- if not parsed_url.scheme and not parsed_url.netloc: # is URL relative?
- payload_headers.update(get_auth_header(cfg.node_cls))
- payload_headers["X-Comfy-Env"] = get_deploy_environment()
+ if not parsed_url.scheme and not parsed_url.netloc: # is URL relative?
+ payload_headers.update(get_auth_header(cfg.node_cls))
+
+ target_netloc = urlparse(url).netloc.lower()
+ base_netloc = urlparse(default_base_url()).netloc.lower()
+ if target_netloc == base_netloc:
+ payload_headers["X-Comfy-Env"] = get_deploy_environment()As per coding guidelines: comfy_api_nodes/**: “Third-party API integration nodes. Focus on … Proper error handling for API failures … [and] Security of user data passed to external APIs.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@comfy_api_nodes/util/client.py` around lines 620 - 623, The X-Comfy-Env
header is only being set inside the "relative URL" branch, so absolute requests
to the Comfy API host miss it; update the logic so
payload_headers["X-Comfy-Env"] is added whenever the request targets the Comfy
API host (either parsed_url has no scheme/netloc or parsed_url.netloc matches
cfg.endpoint.host or cfg.endpoint.netloc), not only for relative URLs. Keep the
existing get_auth_header(cfg.node_cls) behavior for relative URLs but move or
add the X-Comfy-Env assignment to run for both the relative-URL branch and for
absolute URLs whose netloc equals the configured Comfy API endpoint (use
parsed_url, payload_headers, cfg.endpoint to locate/compare).
4de0e4e to
d443728
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
comfy_api_nodes/util/client.py (1)
620-623:⚠️ Potential issue | 🟠 Major
X-Comfy-Envis still not applied to absolute Comfy API URLs.At Line 620, the header is gated by the relative-URL check, so absolute URLs targeting the same API host won’t include
X-Comfy-Env. That leaves environment signaling incomplete versus the PR goal.Suggested fix
- if not parsed_url.scheme and not parsed_url.netloc: # is URL relative? - payload_headers.update(get_auth_header(cfg.node_cls)) - payload_headers["X-Comfy-Env"] = get_deploy_environment() + is_relative = not parsed_url.scheme and not parsed_url.netloc + if is_relative: # relative URL uses default API host and auth + payload_headers.update(get_auth_header(cfg.node_cls)) + + base_netloc = urlparse(default_base_url()).netloc.lower() + target_netloc = parsed_url.netloc.lower() if parsed_url.netloc else base_netloc + if target_netloc == base_netloc: + payload_headers["X-Comfy-Env"] = get_deploy_environment()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@comfy_api_nodes/util/client.py` around lines 620 - 623, The X-Comfy-Env header is only added for relative URLs (parsed_url.scheme/netloc empty); change the condition so X-Comfy-Env is also applied when the request targets the Comfy API host even if an absolute URL is used: update the branch that sets payload_headers (where parsed_url, payload_headers, get_auth_header(cfg.node_cls) and get_deploy_environment() are used) to add X-Comfy-Env when parsed_url.netloc is empty OR parsed_url.netloc equals the Comfy API host (compare parsed_url.netloc against the configured base/API host from cfg, e.g. urlparse(cfg.base_url or cfg.api_url).netloc), leaving other header logic (cfg.endpoint.headers) intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@comfy_api_nodes/util/client.py`:
- Around line 620-623: The X-Comfy-Env header is only added for relative URLs
(parsed_url.scheme/netloc empty); change the condition so X-Comfy-Env is also
applied when the request targets the Comfy API host even if an absolute URL is
used: update the branch that sets payload_headers (where parsed_url,
payload_headers, get_auth_header(cfg.node_cls) and get_deploy_environment() are
used) to add X-Comfy-Env when parsed_url.netloc is empty OR parsed_url.netloc
equals the Comfy API host (compare parsed_url.netloc against the configured
base/API host from cfg, e.g. urlparse(cfg.base_url or cfg.api_url).netloc),
leaving other header logic (cfg.endpoint.headers) intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 20aaffab-13c7-4d73-99e7-67dbe3edda7b
📒 Files selected for processing (3)
.gitignorecomfy/deploy_environment.pycomfy_api_nodes/util/client.py
✅ Files skipped from review due to trivial changes (1)
- .gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
- comfy/deploy_environment.py
Read a .comfy_environment file from the ComfyUI base directory to determine the deployment environment (e.g. standalone, portable, desktop). Defaults to 'local_git' when the file is absent. The value is sent as an X-Comfy-Deploy-Env header on all requests to api.comfy.org, allowing the API to differentiate between environment types. The .comfy_environment file is gitignored so launchers/installers can write it without affecting the repository. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019d939e-6b4d-738b-8d1a-ac7cbf6736a4
d443728 to
e7fbb3c
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@comfy/deploy_environment.py`:
- Around line 14-33: get_deploy_environment currently lazily sets the
module-level _cached_value without any synchronization, so concurrent callers
can race and a temporary read failure can permanently pin _DEFAULT_DEPLOY_ENV;
fix by introducing a module-level lock (e.g., threading.Lock) and surround the
check/read/set of _cached_value with the lock (use double-checked locking: check
_cached_value before acquiring and re-check after acquiring) so only one thread
performs the file open/read logic for _ENV_FILENAME and sets _cached_value
(falling back to _DEFAULT_DEPLOY_ENV on error) while keeping logger warning
behavior intact.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e3340ae7-563e-4db0-a340-61b02aa19c8d
📒 Files selected for processing (3)
.gitignorecomfy/deploy_environment.pycomfy_api_nodes/util/client.py
✅ Files skipped from review due to trivial changes (1)
- .gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
- comfy_api_nodes/util/client.py
| def get_deploy_environment() -> str: | ||
| global _cached_value | ||
| if _cached_value is not None: | ||
| return _cached_value | ||
|
|
||
| env_file = os.path.join(folder_paths.base_path, _ENV_FILENAME) | ||
| try: | ||
| with open(env_file, encoding="utf-8") as f: | ||
| first_line = f.readline().strip() | ||
| value = "".join(c for c in first_line if 32 <= ord(c) < 127) | ||
| if value: | ||
| _cached_value = value | ||
| return _cached_value | ||
| except FileNotFoundError: | ||
| pass | ||
| except Exception as e: | ||
| logger.warning("Failed to read %s: %s", env_file, e) | ||
|
|
||
| _cached_value = _DEFAULT_DEPLOY_ENV | ||
| return _cached_value |
There was a problem hiding this comment.
Synchronize cache initialization to avoid sticky transient fallback.
_cached_value is lazily initialized without a lock. Concurrent first calls can race, and a transient read failure in one caller can pin "local_git" for the rest of the process.
🔧 Proposed fix
import logging
import os
+import threading
import folder_paths
@@
_cached_value: str | None = None
+_cache_lock = threading.Lock()
@@
def get_deploy_environment() -> str:
global _cached_value
if _cached_value is not None:
return _cached_value
+ with _cache_lock:
+ if _cached_value is not None:
+ return _cached_value
- env_file = os.path.join(folder_paths.base_path, _ENV_FILENAME)
- try:
- with open(env_file, encoding="utf-8") as f:
- first_line = f.readline().strip()
- value = "".join(c for c in first_line if 32 <= ord(c) < 127)
- if value:
- _cached_value = value
- return _cached_value
- except FileNotFoundError:
- pass
- except Exception as e:
- logger.warning("Failed to read %s: %s", env_file, e)
+ env_file = os.path.join(folder_paths.base_path, _ENV_FILENAME)
+ try:
+ with open(env_file, encoding="utf-8") as f:
+ first_line = f.readline().strip()
+ value = "".join(c for c in first_line if 32 <= ord(c) < 127)
+ if value:
+ _cached_value = value
+ return _cached_value
+ except FileNotFoundError:
+ pass
+ except Exception as e:
+ logger.warning("Failed to read %s: %s", env_file, e)
+ return _DEFAULT_DEPLOY_ENV
- _cached_value = _DEFAULT_DEPLOY_ENV
- return _cached_value
+ _cached_value = _DEFAULT_DEPLOY_ENV
+ return _cached_valueAs per coding guidelines: comfy/** review should focus on “Thread safety for concurrent execution.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@comfy/deploy_environment.py` around lines 14 - 33, get_deploy_environment
currently lazily sets the module-level _cached_value without any
synchronization, so concurrent callers can race and a temporary read failure can
permanently pin _DEFAULT_DEPLOY_ENV; fix by introducing a module-level lock
(e.g., threading.Lock) and surround the check/read/set of _cached_value with the
lock (use double-checked locking: check _cached_value before acquiring and
re-check after acquiring) so only one thread performs the file open/read logic
for _ENV_FILENAME and sets _cached_value (falling back to _DEFAULT_DEPLOY_ENV on
error) while keeping logger warning behavior intact.
Summary
Adds an
X-Comfy-Envheader to all API requests sent toapi.comfy.org, allowing the API to differentiate between environment types (e.g.local_git,standalone,portable,desktop).Relates to Comfy-Org/ComfyUI-Desktop-2.0-Beta#416
How it works
comfy/deploy_environment.pyreads a.comfy_environmentfile from the ComfyUI base directory.standalone,portable,desktop).local_git.X-Comfy-Envheader on all requests toapi.comfy.org..comfy_environmentfile is gitignored so launchers/installers can write it without affecting the repository.Usage
Launchers or installers simply write a
.comfy_environmentfile in the ComfyUI root directory with the desired value:standaloneNo CLI args or environment variables needed. Git clone users get
local_gitautomatically.API Node PR Checklist
Scope
Pricing & Billing
If Need pricing update:
QA
Comms