Publish workflow (.github/workflows/publish.yml) already existed and was already push-to-main-only / workflow_dispatch with no pull_request_target. Hardened further: - permissions: issues: write -> contents: read (the action never uses GITHUB_TOKEN at all; checkout only needs read access, nothing else) - drop the unused 'master' branch trigger (repo only has main) - add a concurrency group so overlapping publish runs can't race - document, inline, why pull_request_target must never be added here and how the REGISTRY_ACCESS_TOKEN secret is handled (never echoed/logged, passed only as the action's declared input) Also adds docs/registry-compatibility-audit.md: a code-only audit (no README, no template comments) answering the four compatibility questions for pyproject.toml (min Python version, OS support, GPU/CUDA usage, ComfyUI min-version API), each with file:line evidence, plus a proposed pyproject.toml block for manual review. pyproject.toml itself is NOT touched by this PR. No secret is configured or requested by this change, and nothing is published. Node runtime behavior is unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
8.6 KiB
Auditoria de compatibilidade — pyproject.toml / ComfyUI Registry
Investigação do código (não do README, não do template comentado) para decidir
o que é seguro declarar em classifiers, requires-python, Icon/Banner e
requires-comfyui, conforme
docs.comfy.org/registry/specifications.
Este documento é só o relatório. O pyproject.toml não foi alterado —
a proposta está no bloco de código no final, para aplicação manual.
1. Menor versão de Python que o código realmente aceita
Resposta: Python ≥ 3.10.
Evidência: metahub_input_node.py:69
def mask_to_tensor(mask_path: Path | None, width: int, height: int) -> torch.Tensor:
O arquivo não tem from __future__ import annotations (confirmado por busca em
todo o repo), então essa anotação é avaliada em tempo de definição da função,
não como string. Path | None usando o operador | em tipos reais é
PEP 604, introduzido no Python 3.10 — em
3.9 ou anterior isso levanta TypeError: unsupported operand type(s) for |
na hora de importar o módulo, ou seja, o node inteiro falha ao carregar.
Constraint mais fraca, mesma direção: metahub_input_node.py:46
usa -> tuple[dict, str] (PEP 585, genéricos nativos em minúsculo), que exige
apenas 3.9+ — já coberto pelo piso de 3.10 acima.
Não há nenhum outro uso de sintaxe mais nova (sem match/case, sem :=,
sem except*, sem str.removeprefix/removesuffix, sem tomllib) em nenhum
outro arquivo do pacote.
2. Windows / Linux / macOS — funciona igual? Existe caminho platform-dependent?
Resposta: sim, funciona igual nos três. Há só um ponto assimétrico, não-crítico.
- Todo I/O de arquivo passa por
pathlib.Path(não há concatenação manual de string com\ou/, não háos.path.joinplatform-fráigl misturado com literais). Ex.:metahub_input_node.py:20-43,metadata_utils_impl.pyinteiro. - Busca em todo o repo por
sys.platform,os.name,platform.system,ctypes,winreg,msvcrt,os.startfile, chamadas POSIX-only (os.geteuid,fcntl,pwd/grp) esubprocess(..., shell=True): zero ocorrências em qualquer arquivo.pydo pacote. - Único ponto assimétrico:
video_metadata_utils.py:42-51, a lista de fallback de localização doffmpeg(find_ffmpeg_binary) só tem caminhos hard-coded do Windows (C:/ffmpeg/bin/ffmpeg.exeetc.) depois de já ter tentadoFFMPEG_PATHeshutil.which('ffmpeg')— que são cross-platform e cobrem o caso comum em Linux/macOS (ffmpeg instalado via apt/brew fica no PATH). Se não encontrar em nenhum dos dois, o código levanta umRuntimeErrorcom instrução clara (video_metadata_utils.py:317-322) — não trava, não corrompe nada, só falha de forma explícita e igual nas três plataformas quando o ffmpeg realmente não está instalado.
Não há evidência de comportamento diferente ou incorreto em nenhuma
plataforma — só uma heurística de descoberta de binário um pouco mais fraca
fora do Windows. Isso sustenta o classifier OS Independent.
3. Toca em GPU/CUDA/torch, ou é I/O + hashing puro?
Resposta: usa torch, mas nunca como dependência de GPU/CUDA. Nenhuma chamada
de device placement em lugar nenhum do repo (busca por .cuda(, .to(device,
.half(), torch.device — zero ocorrências).
Dois usos, ambos read-only / opcionais:
- Telemetria de GPU, defensiva —
metadata_utils_impl.py:196-256collect_gpu_metrics(): fazimport torchdentro de umtry/except ImportError, depois só lêtorch.cuda.is_available(),torch.cuda.get_device_name(0),torch.cuda.max_memory_allocated(0), e equivalente paratorch.backends.mps. Se CUDA/MPS não existir, cai para"CPU (CUDA not available)"sem erro. Nunca aloca nada na GPU, nunca move um tensor para lá — só introspecciona o que já está rodando. - Criação de tensor CPU para o contrato de tipos do ComfyUI —
metahub_input_node.py:61-76(image_to_tensor,mask_to_tensor): usatorch.from_numpy(array)[None,]para produzir os tiposIMAGE/MASKque o ComfyUI espera. Isso roda em CPU; não há.to()/.cuda()em seguida.
Fora isso, o node é I/O (leitura/escrita de PNG/JPEG/WebP/GLB, subprocess para ffmpeg) + hashing (SHA256 de modelos/LoRAs) + string/JSON building. Ele funciona sem problema em instalações ComfyUI CPU-only.
Conclusão prática: declarar Environment :: GPU :: NVIDIA CUDA (ou
ROCm/Metal) seria uma claim falsa — o node não exige GPU nenhuma para
funcionar, e isso só polui o filtro de busca de quem procura nodes que
realmente precisam de CUDA. Nenhum classifier de acelerador deve ser
adicionado.
4. Existe API do ComfyUI para estabelecer uma versão mínima verificável?
Resposta: não, o código não usa nenhuma.
Os dois únicos pontos de contato com o runtime do ComfyUI além dos hidden
inputs padrão (PROMPT, EXTRA_PNGINFO, UNIQUE_ID — parte estável do
contrato de custom nodes desde as primeiras versões) são:
import folder_paths—metadata_utils_impl.py:59emetadata_utils_impl.py:1091, ambos dentro detry/except, usados só para localizar pastas de modelos / diretório de output. Se falhar, cai para caminhos relativos default.import comfy/comfy.__version__—metadata_utils_impl.py:297-299, também dentro detry/except, usado só para reportar a versão do ComfyUI nos metadados salvos — nunca comparado contra um piso mínimo.
Nenhum desses é usado como gate (não há if comfy_version < X: raise nem
equivalente), e nenhuma API nova/versionada é chamada — nada que dependa de
uma versão específica do ComfyUI para existir.
Conclusão prática: não há piso de versão do ComfyUI provável a partir do
código. Preencher requires-comfyui seria um chute. Se o mantenedor já
validou manualmente uma versão mínima em teste real, isso é um fato externo
ao código-fonte (não deriva de auditoria) e pode ser adicionado depois, com
essa evidência explícita.
Princípio aplicado
Cada campo abaixo só foi preenchido onde havia evidência de código (arquivo:linha) sustentando um limite real. Onde não havia prova, o campo foi omitido, não preenchido "por via das dúvidas".
pyproject.toml proposto (não aplicado — para revisão)
[project]
name = "imagemetahub-comfyui-save"
description = "Official companion node for Image MetaHub. Saves A1111/Civitai-compatible parameters plus extended Image MetaHub metadata (workflow JSON, SHA256 model hashes, VRAM peak/total, GPU device, generation time, and steps/sec) for reproducibility and benchmarking."
version = "1.1.9"
license = {file = "LICENSE"}
requires-python = ">=3.10"
classifiers = [
"Operating System :: OS Independent",
]
dependencies = []
[project.urls]
Repository = "https://github.com/LuqP2/ImageMetaHub-ComfyUI-Save"
# Used by Comfy Registry https://registry.comfy.org
Documentation = "https://github.com/LuqP2/ImageMetaHub-ComfyUI-Save/wiki"
"Bug Tracker" = "https://github.com/LuqP2/ImageMetaHub-ComfyUI-Save/issues"
[tool.comfy]
PublisherId = "image-metahub"
DisplayName = "ImageMetaHub-ComfyUI-Save"
includes = []
# Icon and Banner omitted: no square icon (<=400x400) or 21:9 banner asset
# exists yet. Add them (with real URLs) when they do — an empty string is
# not the same as omitting the field.
# "requires-comfyui" omitted: no code path checks or requires a specific
# ComfyUI version (see docs/registry-compatibility-audit.md, Q4). Add it only
# once a floor version has actually been tested, not as a guess.
Diffs em relação ao atual, e por quê:
| Campo | Atual | Proposto | Motivo |
|---|---|---|---|
requires-python |
ausente | ">=3.10" |
metahub_input_node.py:69 usa Path | None sem from __future__ import annotations |
classifiers |
bloco inteiro comentado | só OS Independent |
nenhum caminho platform-gated encontrado; nenhum classifier de GPU porque o node não exige GPU |
Icon |
"" |
omitido | string vazia ≠ campo omitido; não existe asset ainda |
requires-comfyui |
comentado | continua omitido | nenhuma API de versão mínima é usada no código |