mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2026-05-09 08:32:30 +08:00
Defense-in-depth over GET→POST alone: reject the three CORS-safelisted simple-form Content-Types (x-www-form-urlencoded, multipart/form-data, text/plain) on 16 no-body POST handlers (glob + legacy) to block <form method=POST> CSRF that bypasses method-only gating. Move comfyui_switch_version to a JSON body so the preflight requirement applies. Split db_mode/policy/update/channel_url_list into GET(read) + POST(write). Tighten do_fix (high → high+) and gate three previously-ungated config setters at middle. Resynchronize openapi.yaml (27 paths, 30 operations, ComfyUISwitchVersionParams as a shared $ref component). Add E2E harness variants, Playwright config, CSRF/secgate suites, 39-endpoint coverage, and a CHANGELOG. Breaking: legacy per-op POST routes (install/uninstall/fix/disable/update/ reinstall/abort_current) are removed; callers already use queue/batch. Legacy /manager/notice (v1) is removed; /v2/manager/notice is retained. Reported-by: XlabAI Team of Tencent Xuanwu Lab CVSS: 8.1 (AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H)
425 lines
16 KiB
Markdown
425 lines
16 KiB
Markdown
# Scenario Intent Mapping
|
|
|
|
**Generated**: 2026-04-18
|
|
**Definition of "intent"**: For each scenario — **what real use case, user need, or protection concern does this scenario represent?** Answers "why does this scenario matter, what is it there to prove?"
|
|
|
|
Intent categories used:
|
|
- **User capability** — the user wants to accomplish task X
|
|
- **Data integrity** — the system must not corrupt state
|
|
- **Security boundary** — privilege / access must be enforced
|
|
- **Input resilience** — bad input must not crash or mis-operate
|
|
- **Idempotency** — operation can be retried safely
|
|
- **Observability** — the caller needs accurate state visibility
|
|
- **Concurrency safety** — parallel calls don't interfere
|
|
- **Recovery** — system can recover from failure / bad state
|
|
|
|
---
|
|
|
|
# Section 1 — Glob v2 Endpoints
|
|
|
|
## 1.1 Queue Management
|
|
|
|
### POST /v2/manager/queue/task (install)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success (CNR) | User capability: install a registered pack at a specific version for reproducibility |
|
|
| Success (nightly/URL) | User capability: install unreleased or private pack from arbitrary git URL |
|
|
| Success (skip_post_install + already disabled) | Recovery: re-enable a previously disabled pack without full reinstall (optimization path) |
|
|
| Validation error (bad kind) | Input resilience: prevent arbitrary op execution via malformed kind; ensure schema gate is the truth |
|
|
| Validation error (missing ui_id/client_id) | Observability: every queued task must be traceable back to its originator |
|
|
| Invalid JSON body | Input resilience: malformed bytes don't crash the server |
|
|
| Worker auto-start | User capability: ease of use — installer doesn't need separate "start" call (legacy path does though) |
|
|
|
|
### POST /v2/manager/queue/task (uninstall)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: remove a pack that's no longer needed or causing issues |
|
|
| Target not installed | Idempotency: uninstall of non-present pack should not fail destructively |
|
|
|
|
### POST /v2/manager/queue/task (update)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: upgrade to a newer release to get fixes/features |
|
|
| Already up-to-date | Idempotency: safe to trigger update even when nothing new exists |
|
|
| Update fails mid-way | Data integrity: don't leave pack in partially-updated state |
|
|
|
|
### POST /v2/manager/queue/task (fix)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Recovery: when dependencies drift or break, re-install them without re-cloning source |
|
|
| Missing deps pre-fix | Recovery: fix should heal the environment |
|
|
|
|
### POST /v2/manager/queue/task (disable)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: temporarily stop using a pack without losing it (reversible) |
|
|
| Already disabled | Idempotency: re-disable is a no-op |
|
|
|
|
### POST /v2/manager/queue/task (enable)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: restore a disabled pack to active use |
|
|
| Not disabled | Idempotency: no-op when already active |
|
|
|
|
### POST /v2/manager/queue/install_model
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: download models from curated whitelist for model library |
|
|
| Missing client_id/ui_id | Observability: every download is traceable |
|
|
| Invalid metadata | Input resilience: malformed model requests rejected early |
|
|
| Not in whitelist | Security boundary: prevent arbitrary URL downloads (supply-chain protection) |
|
|
| Non-safetensors + lower security | Security boundary: block executable-format model files in lower-trust env |
|
|
|
|
### POST /v2/manager/queue/update_all
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: one-click update of all installed packs |
|
|
| Security denied | Security boundary: bulk ops are more risky; require middle+ trust |
|
|
| Missing params | Observability: must know who initiated bulk op |
|
|
| mode=local | User capability: work offline using cached data |
|
|
| Desktop build | Data integrity: don't self-update comfyui-manager in bundled builds |
|
|
| Empty active set | Idempotency: safe to run on fresh install with nothing to update |
|
|
|
|
### POST /v2/manager/queue/update_comfyui
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: update ComfyUI core itself |
|
|
| Missing params | Observability: traceability |
|
|
| stable=true explicit | User capability: override policy for one-off stable update regardless of config |
|
|
|
|
### POST /v2/manager/queue/reset
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Recovery: abort an in-progress batch; clear failed state |
|
|
| Already empty | Idempotency: safe to call repeatedly as cleanup |
|
|
|
|
### POST /v2/manager/queue/start
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Worker not running | User capability: explicit trigger for the async worker |
|
|
| Already running | Concurrency safety: don't spawn duplicate workers (data corruption risk) |
|
|
| Empty queue | Idempotency: no error on empty queue |
|
|
|
|
### GET /v2/manager/queue/status
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| No filter | Observability: dashboard view of overall progress |
|
|
| client_id filter | Observability: per-client progress for multi-user UI |
|
|
| Unknown client_id | Input resilience: unknown id returns 0s, not error |
|
|
|
|
### GET /v2/manager/queue/history
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| id=<batch_id> | Observability: inspect an old batch for audit/debug |
|
|
| Path traversal | Security boundary: prevent arbitrary file reads via history endpoint |
|
|
| ui_id filter | Observability: detailed view for one task |
|
|
| client_id filter | Observability: per-client history |
|
|
| Pagination | Performance: avoid huge payload on long histories |
|
|
| Serialization failure | Input resilience: fail cleanly (400) rather than crash |
|
|
|
|
### GET /v2/manager/queue/history_list
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Observability: enumerate past batches |
|
|
| Empty | Idempotency: no crash on empty history dir |
|
|
| Path inaccessible | Input resilience: fail cleanly |
|
|
|
|
## 1.2 Custom Node Info
|
|
|
|
### GET /v2/customnode/getmappings
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success (mode=local/cache/remote) | User capability: UI resolves "missing nodes in workflow" to recommend packs |
|
|
| mode=nickname | User capability: shorter display names for UI |
|
|
| Missing mode | Input resilience: require explicit mode choice |
|
|
|
|
### GET /v2/customnode/fetch_updates (deprecated)
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Always 410 | API contract: signal clients to migrate to queue-based flow; don't silently break |
|
|
|
|
### GET /v2/customnode/installed
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| mode=default | Observability: current state for UI |
|
|
| mode=imported | Observability: startup-time state for diff ("what changed since boot") |
|
|
| Empty | Idempotency: no crash on empty install |
|
|
|
|
### POST /v2/customnode/import_fail_info
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Known failed pack | Recovery: show user exact traceback so they can decide fix vs report vs uninstall |
|
|
| Unknown pack | Input resilience: 400 rather than empty success (distinguishable) |
|
|
| Missing fields / non-dict | Input resilience: reject early |
|
|
|
|
### POST /v2/customnode/import_fail_info_bulk
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| cnr_ids list | Performance: batch lookup for dialog that shows multiple failed packs at once |
|
|
| urls list | Same, for git-URL-installed packs |
|
|
| Empty lists | Input resilience: require at least one query |
|
|
| Null for unknown | Observability: distinguish "no failure info" from "lookup failed" |
|
|
|
|
## 1.3 Snapshots
|
|
|
|
### GET /v2/snapshot/get_current
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Observability: inspect system state before taking a snapshot |
|
|
| Failure | Input resilience: fail cleanly |
|
|
|
|
### POST /v2/snapshot/save
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: persist current state for later rollback |
|
|
| Multiple saves | Observability: each save is independently retrievable |
|
|
|
|
### GET /v2/snapshot/getlist
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: choose which snapshot to restore/delete |
|
|
| Empty | Idempotency: no crash on empty snapshot dir |
|
|
|
|
### POST /v2/snapshot/remove
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: housekeeping (remove old snapshots) |
|
|
| Nonexistent target | Idempotency: re-delete should not error |
|
|
| Path traversal | Security boundary: prevent deleting files outside snapshot dir |
|
|
| Missing target | Input resilience |
|
|
| Security denied | Security boundary: middle security required |
|
|
|
|
### POST /v2/snapshot/restore
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Recovery: rollback to a known-good state after bad update |
|
|
| Nonexistent | Input resilience |
|
|
| Path traversal | Security boundary |
|
|
| Security denied | Security boundary: middle+ required (restore is destructive) |
|
|
|
|
## 1.4 Configuration
|
|
|
|
### GET /v2/manager/db_mode
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Observability: UI shows current mode setting |
|
|
|
|
### POST /v2/manager/db_mode
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Valid | User capability: switch between online/local DB for different network conditions |
|
|
| Malformed | Input resilience |
|
|
| Missing value | Input resilience: don't silently set unknown/empty |
|
|
|
|
### GET/POST /v2/manager/policy/update
|
|
|
|
Same as db_mode: observability of current policy + user choice to change update strategy (stable vs nightly) + input resilience.
|
|
|
|
### GET /v2/manager/channel_url_list
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Observability: show available channels in UI dropdown |
|
|
| "custom" selected | Input resilience: URL not in known list doesn't break display |
|
|
|
|
### POST /v2/manager/channel_url_list
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Known name | User capability: switch between upstream vs fork vs private channel |
|
|
| Unknown name | Input resilience: silent no-op (don't crash on typo) |
|
|
| Malformed | Input resilience |
|
|
|
|
## 1.5 System
|
|
|
|
### GET /v2/manager/is_legacy_manager_ui
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: frontend picks which UI variant to mount at page load |
|
|
|
|
### GET /v2/manager/version
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | Observability: display version in UI (troubleshooting / support) |
|
|
| Idempotent | Data integrity: version doesn't change at runtime |
|
|
|
|
### POST /v2/manager/reboot
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: apply changes that require restart (snapshot restore, ComfyUI version switch) |
|
|
| CLI session mode | Integration: cooperates with external process manager for clean restart |
|
|
| Security denied | Security boundary: middle required (restart affects all users) |
|
|
|
|
### GET /v2/comfyui_manager/comfyui_versions
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: enumerate ComfyUI versions to pick one for rollback/upgrade |
|
|
| Git failure | Input resilience: fail cleanly if ComfyUI isn't a git repo |
|
|
|
|
### POST /v2/comfyui_manager/comfyui_switch_version
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: switch ComfyUI to specific version (pin for reproducibility) |
|
|
| Missing params | Observability |
|
|
| Security denied | Security boundary: high+ required (massive blast radius — affects core behavior) |
|
|
|
|
---
|
|
|
|
# Section 2 — Legacy-only Endpoints
|
|
|
|
### POST /v2/manager/queue/batch
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Single-kind batch | User capability: execute multiple operations of same type in one round-trip |
|
|
| Mixed-kind batch | User capability: apply a workflow (uninstall-then-install = reinstall) atomically |
|
|
| Partial failure (`failed` list) | Observability: distinguish which packs in the batch failed from ones that succeeded |
|
|
| Empty body | Idempotency: no-op if nothing to do |
|
|
| update_all sub-key | User capability: trigger bulk update as part of batch |
|
|
|
|
### GET /v2/customnode/getlist
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: populate Custom Nodes Manager dialog with full available pack catalog |
|
|
| skip_update=true | Performance: fast load when user doesn't need remote fetch |
|
|
| Channel resolution | Observability: user sees which channel data came from |
|
|
|
|
### GET /customnode/alternatives
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: recommend alternative packs when one is discontinued/unavailable |
|
|
|
|
### GET /v2/externalmodel/getlist
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: browse curated model catalog |
|
|
| `installed` flag per model | Observability: which models already present |
|
|
| HuggingFace sentinel | User capability: HF-hosted models via standard URL |
|
|
| Custom save_path | User capability: custom model placement |
|
|
|
|
### GET /v2/customnode/versions/{node_name}
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Known CNR | User capability: pick a specific version to install (stability over latest) |
|
|
| Unknown pack | Input resilience |
|
|
|
|
### GET /v2/customnode/disabled_versions/{node_name}
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Has disabled | User capability: see what versions are available to re-enable without fresh install |
|
|
| None | Input resilience |
|
|
|
|
### POST /v2/customnode/install/git_url
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: install arbitrary git pack (for advanced users / private packs) |
|
|
| Already installed | Idempotency |
|
|
| Clone failure | Input resilience: bad URL returns error; no corrupt state |
|
|
| Security denied | Security boundary: high+ required (arbitrary code execution risk) |
|
|
|
|
### POST /v2/customnode/install/pip
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| Success | User capability: install pip packages needed by a pack |
|
|
| Security denied | Security boundary: high+ required (arbitrary package execution risk) |
|
|
|
|
### GET /v2/manager/notice
|
|
|
|
| Scenario | Intent |
|
|
|---|---|
|
|
| GitHub reachable | User capability: see latest Manager news/changelog inline |
|
|
| GitHub unreachable | Input resilience: don't block UI on external service failure |
|
|
| Non-git ComfyUI | Observability: warn user that their install is non-standard |
|
|
| Outdated ComfyUI | Observability: warn user they're too old to be safe |
|
|
| Desktop variant | User capability: correct footer for desktop distribution |
|
|
|
|
---
|
|
|
|
# Section 3 — Cross-cutting Scenarios
|
|
|
|
Some scenarios recur across many endpoints with consistent intent:
|
|
|
|
| Scenario pattern | Applies to | Unified intent |
|
|
|---|---|---|
|
|
| Malformed JSON body | all POST endpoints accepting JSON | Input resilience — protect against corrupted bytes / wrong content-type |
|
|
| Missing required field | all POST endpoints with schemas | Input resilience + Observability (traceability fields mandatory) |
|
|
| Path traversal in target/id | snapshot/remove, snapshot/restore, queue/history | Security boundary — prevent arbitrary filesystem access |
|
|
| Security level denial (middle/middle+/high+) | destructive endpoints | Security boundary — tier privileged ops per deployment risk profile |
|
|
| Idempotent re-call on empty state | queue/reset, history_list, snapshot/getlist, installed | Idempotency — safe to poll or retry |
|
|
| Repeated read returns same value | version, db_mode, policy/update | Data integrity — config/runtime state is stable |
|
|
| Empty collection returned cleanly | history, getlist, installed, alternatives | Input resilience — empty is valid, not an error |
|
|
|
|
---
|
|
|
|
# Section 4 — Intent Coverage Summary
|
|
|
|
| Intent category | # scenarios | Notes |
|
|
|---|---:|---|
|
|
| User capability (positive user need) | 62 | The "happy paths" |
|
|
| Input resilience | 32 | Mostly 400s for bad input |
|
|
| Security boundary | 15 | Security levels + path traversal |
|
|
| Idempotency | 14 | No-op / retry safety |
|
|
| Observability | 16 | State visibility + traceability |
|
|
| Data integrity | 8 | Config/state stability |
|
|
| Recovery | 5 | Fix, restore, reset |
|
|
| Concurrency safety | 2 | Worker dedup |
|
|
|
|
Total unique scenarios mapped: ~154 (matches Report A).
|
|
|
|
---
|
|
|
|
# Section 5 — Why This Mapping Matters
|
|
|
|
For each scenario, the **intent** drives the TEST design:
|
|
- **User capability** scenarios need end-to-end effect verification (feature works as promised)
|
|
- **Input resilience** scenarios need negative tests (bad inputs rejected cleanly)
|
|
- **Security boundary** scenarios need permission gate tests (403 proven per security level)
|
|
- **Idempotency** scenarios need repeat-call tests (no state drift)
|
|
- **Observability** scenarios need response-correctness tests (UI can trust the data)
|
|
- **Data integrity** scenarios need consistency tests (no runtime mutation of constants)
|
|
- **Recovery** scenarios need fault-injection tests (broken state → fix heals it)
|
|
- **Concurrency safety** scenarios need parallel-call tests (no duplicate workers/tasks)
|
|
|
|
Gaps in current E2E suite are best understood by intent: missing tests are typically for **security boundary** (403 gates), **input resilience edge cases** (path traversal, missing value keys), and **recovery** (fix/restore). These are the hardest to reach in simple E2E but matter most for production safety.
|
|
|
|
---
|
|
*End of Scenario Intent Mapping*
|