Fix #46 enable node blacklisting using --blacklist-custom-nodes ComfyUI-Manager / config.blacklist_custom_nodes = ["ComfyUI-Manager"]

This commit is contained in:
doctorpangloss 2025-09-23 13:50:05 -07:00
parent 2a881a768e
commit ac0694a7bd
9 changed files with 155 additions and 88 deletions

170
README.md
View File

@ -696,86 +696,67 @@ You can pass additional extra model path configurations with one or more copies
### Command Line Arguments
```
usage: comfyui.exe [-h] [-c CONFIG_FILE]
[--write-out-config-file CONFIG_OUTPUT_PATH] [-w CWD]
[--base-paths BASE_PATHS [BASE_PATHS ...]] [-H [IP]]
[--port PORT] [--enable-cors-header [ORIGIN]]
[--max-upload-size MAX_UPLOAD_SIZE]
[--base-directory BASE_DIRECTORY]
[--extra-model-paths-config PATH [PATH ...]]
[--output-directory OUTPUT_DIRECTORY]
[--temp-directory TEMP_DIRECTORY]
[--input-directory INPUT_DIRECTORY] [--auto-launch]
[--disable-auto-launch] [--cuda-device DEVICE_ID]
[--cuda-malloc | --disable-cuda-malloc]
[--force-fp32 | --force-fp16 | --force-bf16]
[--fp32-unet | --fp64-unet | --bf16-unet | --fp16-unet | --fp8_e4m3fn-unet | --fp8_e5m2-unet | --fp8_e8m0fnu-unet]
[--fp16-vae | --fp32-vae | --bf16-vae] [--cpu-vae]
[--fp8_e4m3fn-text-enc | --fp8_e5m2-text-enc | --fp16-text-enc | --fp32-text-enc | --bf16-text-enc]
[--directml [DIRECTML_DEVICE]]
[--oneapi-device-selector SELECTOR_STRING]
[--disable-ipex-optimize] [--supports-fp8-compute]
[--preview-method [none,auto,latent2rgb,taesd]]
[--preview-size PREVIEW_SIZE]
[--cache-classic | --cache-lru CACHE_LRU | --cache-none]
[--use-split-cross-attention | --use-quad-cross-attention | --use-pytorch-cross-attention | --use-sage-attention | --use-flash-attention]
[--disable-xformers]
[--force-upcast-attention | --dont-upcast-attention]
[--gpu-only | --highvram | --normalvram | --lowvram | --novram | --cpu]
[--reserve-vram RESERVE_VRAM] [--async-offload]
[--default-hashing-function {md5,sha1,sha256,sha512}]
[--disable-smart-memory] [--deterministic]
[--fast [FAST ...]] [--mmap-torch-files] [--disable-mmap]
[--dont-print-server] [--quick-test-for-ci]
[--windows-standalone-build] [--disable-metadata]
[--disable-all-custom-nodes]
[--whitelist-custom-nodes WHITELIST_CUSTOM_NODES [WHITELIST_CUSTOM_NODES ...]]
[--disable-api-nodes] [--multi-user] [--create-directories]
[--log-stdout]
[--plausible-analytics-base-url PLAUSIBLE_ANALYTICS_BASE_URL]
[--plausible-analytics-domain PLAUSIBLE_ANALYTICS_DOMAIN]
[--analytics-use-identity-provider]
[--distributed-queue-connection-uri DISTRIBUTED_QUEUE_CONNECTION_URI]
[--distributed-queue-worker] [--distributed-queue-frontend]
[--distributed-queue-name DISTRIBUTED_QUEUE_NAME]
[--external-address EXTERNAL_ADDRESS]
[--logging-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
[--disable-known-models] [--max-queue-size MAX_QUEUE_SIZE]
[--otel-service-name OTEL_SERVICE_NAME]
[--otel-service-version OTEL_SERVICE_VERSION]
[--otel-exporter-otlp-endpoint OTEL_EXPORTER_OTLP_ENDPOINT]
[--force-channels-last] [--force-hf-local-dir-mode]
[--front-end-version FRONT_END_VERSION]
[--panic-when PANIC_WHEN] [--front-end-root FRONT_END_ROOT]
[--executor-factory EXECUTOR_FACTORY]
[--openai-api-key OPENAI_API_KEY]
[--ideogram-api-key IDEOGRAM_API_KEY]
[--anthropic-api-key ANTHROPIC_API_KEY]
[--user-directory USER_DIRECTORY]
[--enable-compress-response-body]
[--comfy-api-base COMFY_API_BASE]
[--database-url DATABASE_URL]
[--workflows WORKFLOWS [WORKFLOWS ...]]
[--blip-model-url BLIP_MODEL_URL]
[--blip-model-vqa-url BLIP_MODEL_VQA_URL]
[--sam-model-vith-url SAM_MODEL_VITH_URL]
[--sam-model-vitl-url SAM_MODEL_VITL_URL]
[--sam-model-vitb-url SAM_MODEL_VITB_URL]
[--history-display-limit HISTORY_DISPLAY_LIMIT]
[--ffmpeg-bin-path FFMPEG_BIN_PATH]
[--ffmpeg-extra-codecs FFMPEG_EXTRA_CODECS]
[--wildcards-path WILDCARDS_PATH]
[--wildcard-api WILDCARD_API]
[--photoprism-host PHOTOPRISM_HOST]
[--immich-host IMMICH_HOST]
[--ideogram-session-cookie IDEOGRAM_SESSION_COOKIE]
[--use-symlinks] [--ort-providers ORT_PROVIDERS]
[--vfi-ops-backend VFI_OPS_BACKEND]
[--dependency-version DEPENDENCY_VERSION] [--mmdet-skip]
[--sam-editor-cpu] [--sam-editor-model SAM_EDITOR_MODEL]
[--custom-wildcards CUSTOM_WILDCARDS]
[--disable-gpu-opencv]
usage: comfyui [-h] [-c CONFIG_FILE]
[--write-out-config-file CONFIG_OUTPUT_PATH] [-w CWD]
[--base-paths BASE_PATHS [BASE_PATHS ...]] [-H [IP]]
[--port PORT] [--enable-cors-header [ORIGIN]]
[--max-upload-size MAX_UPLOAD_SIZE]
[--base-directory BASE_DIRECTORY]
[--extra-model-paths-config PATH [PATH ...]]
[--output-directory OUTPUT_DIRECTORY]
[--temp-directory TEMP_DIRECTORY]
[--input-directory INPUT_DIRECTORY] [--auto-launch]
[--disable-auto-launch] [--cuda-device DEVICE_ID]
[--default-device DEFAULT_DEVICE_ID]
[--cuda-malloc | --disable-cuda-malloc]
[--force-fp32 | --force-fp16 | --force-bf16]
[--fp32-unet | --fp64-unet | --bf16-unet | --fp16-unet | --fp8_e4m3fn-unet | --fp8_e5m2-unet | --fp8_e8m0fnu-unet]
[--fp16-vae | --fp32-vae | --bf16-vae] [--cpu-vae]
[--fp8_e4m3fn-text-enc | --fp8_e5m2-text-enc | --fp16-text-enc | --fp32-text-enc | --bf16-text-enc]
[--directml [DIRECTML_DEVICE]]
[--oneapi-device-selector SELECTOR_STRING]
[--disable-ipex-optimize] [--supports-fp8-compute]
[--preview-method [none,auto,latent2rgb,taesd]]
[--preview-size PREVIEW_SIZE]
[--cache-classic | --cache-lru CACHE_LRU | --cache-none]
[--use-split-cross-attention | --use-quad-cross-attention | --use-pytorch-cross-attention | --use-sage-attention | --use-flash-attention]
[--disable-xformers]
[--force-upcast-attention | --dont-upcast-attention]
[--gpu-only | --highvram | --normalvram | --lowvram | --novram | --cpu]
[--reserve-vram RESERVE_VRAM] [--async-offload]
[--force-non-blocking]
[--default-hashing-function {md5,sha1,sha256,sha512}]
[--disable-smart-memory] [--deterministic] [--fast [FAST ...]]
[--mmap-torch-files] [--disable-mmap] [--dont-print-server]
[--quick-test-for-ci] [--windows-standalone-build]
[--disable-metadata] [--disable-all-custom-nodes]
[--whitelist-custom-nodes WHITELIST_CUSTOM_NODES [WHITELIST_CUSTOM_NODES ...]]
[--blacklist-custom-nodes BLACKLIST_CUSTOM_NODES [BLACKLIST_CUSTOM_NODES ...]]
[--disable-api-nodes] [--multi-user] [--create-directories]
[--log-stdout]
[--plausible-analytics-base-url PLAUSIBLE_ANALYTICS_BASE_URL]
[--plausible-analytics-domain PLAUSIBLE_ANALYTICS_DOMAIN]
[--analytics-use-identity-provider]
[--distributed-queue-connection-uri DISTRIBUTED_QUEUE_CONNECTION_URI]
[--distributed-queue-worker] [--distributed-queue-frontend]
[--distributed-queue-name DISTRIBUTED_QUEUE_NAME]
[--external-address EXTERNAL_ADDRESS]
[--logging-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
[--disable-known-models] [--max-queue-size MAX_QUEUE_SIZE]
[--otel-service-name OTEL_SERVICE_NAME]
[--otel-service-version OTEL_SERVICE_VERSION]
[--otel-exporter-otlp-endpoint OTEL_EXPORTER_OTLP_ENDPOINT]
[--force-channels-last] [--force-hf-local-dir-mode]
[--front-end-version FRONT_END_VERSION]
[--panic-when PANIC_WHEN] [--front-end-root FRONT_END_ROOT]
[--executor-factory EXECUTOR_FACTORY]
[--openai-api-key OPENAI_API_KEY]
[--ideogram-api-key IDEOGRAM_API_KEY]
[--anthropic-api-key ANTHROPIC_API_KEY]
[--user-directory USER_DIRECTORY]
[--enable-compress-response-body]
[--comfy-api-base COMFY_API_BASE] [--database-url DATABASE_URL]
[--workflows WORKFLOWS [WORKFLOWS ...]]
options:
-h, --help show this help message and exit
-c CONFIG_FILE, --config CONFIG_FILE
@ -829,7 +810,11 @@ options:
COMFYUI_DISABLE_AUTO_LAUNCH]
--cuda-device DEVICE_ID
Set the id of the cuda device this instance will use.
[env var: COMFYUI_CUDA_DEVICE]
All other devices will not be visible. [env var:
COMFYUI_CUDA_DEVICE]
--default-device DEFAULT_DEVICE_ID
Set the id of the default device, all other devices
will stay visible. [env var: COMFYUI_DEFAULT_DEVICE]
--cuda-malloc Enable cudaMallocAsync (enabled by default for torch
2.0 and up). [env var: COMFYUI_CUDA_MALLOC]
--disable-cuda-malloc
@ -941,13 +926,17 @@ options:
COMFYUI_RESERVE_VRAM]
--async-offload Use async weight offloading. [env var:
COMFYUI_ASYNC_OFFLOAD]
--force-non-blocking Force ComfyUI to use non-blocking operations for all
applicable tensors. This may improve performance on
some non-Nvidia systems but can cause issues with some
workflows. [env var: COMFYUI_FORCE_NON_BLOCKING]
--default-hashing-function {md5,sha1,sha256,sha512}
Allows you to choose the hash function to use for
duplicate filename / contents comparison. Default is
sha256. [env var: COMFYUI_DEFAULT_HASHING_FUNCTION]
--disable-smart-memory
Force ComfyUI to agressively offload to regular ram
instead of keeping models in vram when it can. [env
Force ComfyUI to aggressively offload to regular ram
instead of keeping models in VRAM when it can. [env
var: COMFYUI_DISABLE_SMART_MEMORY]
--deterministic Make pytorch use slower deterministic algorithms when
it can. Note that this might not make images
@ -957,7 +946,8 @@ options:
deteriorating optimizations. Pass a list specific
optimizations if you only want to enable specific
ones. Current valid optimizations: fp16_accumulation
fp8_matrix_mult cublas_ops [env var: COMFYUI_FAST]
fp8_matrix_mult cublas_ops autotune [env var:
COMFYUI_FAST]
--mmap-torch-files Use mmap when loading ckpt/pt files. [env var:
COMFYUI_MMAP_TORCH_FILES]
--disable-mmap Don't use mmap when loading safetensors. [env var:
@ -980,6 +970,10 @@ options:
Specify custom node folders to load even when
--disable-all-custom-nodes is enabled. [env var:
COMFYUI_WHITELIST_CUSTOM_NODES]
--blacklist-custom-nodes BLACKLIST_CUSTOM_NODES [BLACKLIST_CUSTOM_NODES ...]
Specify custom node folders to never load. Accepts
shell-style globs. [env var:
COMFYUI_BLACKLIST_CUSTOM_NODES]
--disable-api-nodes Disable loading all api nodes. [env var:
COMFYUI_DISABLE_API_NODES]
--multi-user Enables per-user storage. [env var:
@ -1119,10 +1113,10 @@ options:
standard in. [env var: COMFYUI_WORKFLOWS]
Args that start with '--' can also be set in a config file (config.yaml or
config.json or specified via -c). Config file syntax allows: key=value,
flag=true, stuff=[a,b,c] (for details, see syntax at https://goo.gl/R74nmi).
In general, command-line values override environment variables which override
config file values which override defaults.
config.json or config.cfg or config.ini or specified via -c). Config file
syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at
https://goo.gl/R74nmi). In general, command-line values override environment
variables which override config file values which override defaults.
```

View File

@ -148,6 +148,7 @@ def _create_parser() -> EnhancedConfigArgParser:
parser.add_argument("--disable-metadata", action="store_true", help="Disable saving prompt metadata in files.")
parser.add_argument("--disable-all-custom-nodes", action="store_true", help="Disable loading all custom nodes.")
parser.add_argument("--whitelist-custom-nodes", type=str, nargs='+', default=[], help="Specify custom node folders to load even when --disable-all-custom-nodes is enabled.")
parser.add_argument("--blacklist-custom-nodes", type=str, nargs='+', default=[], help="Specify custom node folders to never load. Accepts shell-style globs.")
parser.add_argument("--disable-api-nodes", action="store_true", help="Disable loading all api nodes.")
parser.add_argument("--multi-user", action="store_true", help="Enables per-user storage.")

View File

@ -166,6 +166,7 @@ class Configuration(dict):
front_end_root (Optional[str]): The local filesystem path to the directory where the frontend is located. Overrides --front-end-version.
comfy_api_base (str): Set the base URL for the ComfyUI API. (default: https://api.comfy.org)
database_url (str): Specify the database URL, e.g. for an in-memory database you can use 'sqlite:///:memory:'.
blacklist_custom_nodes (list[str]): Specify custom node folders to never load. Accepts shell-style globs.
whitelist_custom_nodes (list[str]): Specify custom node folders to load even when --disable-all-custom-nodes is enabled.
default_device (Optional[int]): Set the id of the default device, all other devices will stay visible.
"""
@ -234,6 +235,7 @@ class Configuration(dict):
self.windows_standalone_build: bool = False
self.disable_metadata: bool = False
self.disable_all_custom_nodes: bool = False
self.blacklist_custom_nodes: list[str] = []
self.whitelist_custom_nodes: list[str] = []
self.multi_user: bool = False
self.plausible_analytics_base_url: Optional[str] = None

View File

@ -5,6 +5,7 @@ import importlib.util
import logging
import os
import sys
import fnmatch
import time
import types
from contextlib import contextmanager
@ -222,6 +223,9 @@ def _vanilla_load_custom_nodes_2(node_paths: Iterable[str]) -> ExportedNodes:
if args.disable_all_custom_nodes and possible_module not in args.whitelist_custom_nodes:
logger.info(f"Skipping {possible_module} due to disable_all_custom_nodes and whitelist_custom_nodes")
continue
if any(fnmatch.fnmatch(possible_module, pattern) for pattern in args.blacklist_custom_nodes):
logger.info(f"Skipping {possible_module} due to blacklist_custom_nodes")
continue
time_before = time.perf_counter()
possible_exported_nodes = _vanilla_load_custom_nodes_1(module_path, ignore=base_node_names)
# comfyui-manager mitigation

View File

@ -0,0 +1,18 @@
from comfy.nodes.package_typing import CustomNode, InputTypes, FunctionReturnsUIVariables
class ShouldNotExist(CustomNode):
@classmethod
def INPUT_TYPES(cls) -> InputTypes:
return {"required": {}}
FUNCTION = "execute"
OUTPUT_NODE = True
def execute(self) -> tuple[...,]:
return None,
NODE_CLASS_MAPPINGS = {
"ShouldNotExist": ShouldNotExist
}

View File

@ -0,0 +1,48 @@
import pytest
from importlib.resources import files
from comfy.api.components.schema.prompt import Prompt
from comfy.cli_args_types import Configuration
from comfy.client.embedded_comfy_client import Comfy
_TEST_WORKFLOW_1 = {
"0": {
"inputs": {},
"class_type": "ShouldNotExist",
"_meta": {
"title": ""
}
},
"1": {
"inputs": {},
"class_type": "TestPath",
"_meta": {
"title": ""
}
}
}
_TEST_WORKFLOW_2 = {
"1": {
"inputs": {},
"class_type": "TestPath",
"_meta": {
"title": ""
}
}
}
@pytest.mark.asyncio
async def test_blacklist_node():
config = Configuration(blacklist_custom_nodes=['issue_46'])
# for finding the custom nodes
config.base_paths = [str(files(__package__))]
async with Comfy(config) as client:
from comfy.cmd.execution import validate_prompt
res = await validate_prompt("1", prompt=_TEST_WORKFLOW_1, partial_execution_list=[])
assert "ShouldNotExist" in res.error["message"]
assert res.error["type"] == "invalid_prompt"
res = await validate_prompt("2", prompt=_TEST_WORKFLOW_2, partial_execution_list=[])
assert "TestPath" not in res.error, "successfully loaded issue_25 nodes"