4 Commits
Author SHA1 Message Date
StarAsh042 83e54f76f6 fix(core): 收紧路径边界并新增管理员白名单 (#16)
* feat(core): stream CSV records and add a configurable read limit

CSV reading used to build a full List[List[str]] of the raw file before
parsing, so cold loads kept both the raw rows and the final objects in
memory at once. Records now stream straight into the parsers.

- artists: _read() feeds _iter_csv_rows() into parse_artist_rows() instead
  of _csv_rows(); a shared _iter_csv_rows() owns counting, early stop and
  error containment for both read paths.
- characters: build_records() is rewritten as a single pass and accepts
  Iterable. The previous Sequence signature iterated twice, so a generator
  input silently dropped the first data row (6 rows -> 4 records, no error).
- characters: load_records()/load_index() read via the new
  ArtistRepository.open_rows(), so the raw rows are no longer parked in
  _rows_cache. load_rows() stays as the public compatibility entry.
- limits: normalize_max_rows()/resolve_max_rows() accept only None or a
  positive integer. The effective limit is part of every cache key, and the
  count is defined once for both paths: csv.reader records, header and
  blank records included.
- exact-N no longer claims truncation: the streaming reader flags
  "truncated" only when it actually reaches record N+1, with no extra read.
- nodes: both take an optional csv_max_rows (default 0 = unlimited),
  appended last in optional and in the signature, marked advanced. ComfyUI
  1.55.18 restores widgets_values positionally (NamedValuesRestore is off
  by default), so appending at the end is what keeps old workflows intact.

Default behaviour is unchanged: same seeds produce byte-identical output
for both nodes.

* fix(core): tighten path boundaries and add administrator allowlists

Two boundary defects in ra_core/paths.py, plus an opt-in allowlist channel
for administrators who want to narrow the allowed roots.

- _resolve_unc_to_drive() used to map the admin-share form of ANY host to a
  local drive: \\evil-host\D$\data\x.csv became D:\data\x.csv and was then
  ALLOWED. The local path was what actually got opened, so the remote intent
  was silently downgraded to a local read/write. Only localhost, 127.0.0.1
  and [::1] are restored now; every other host stays UNC and is rejected by
  the existing UNC branch.
- _is_within() compared os.path.commonpath() against the root without
  normcase, so mixed-case nesting was judged outside. Under the existing
  blacklist this was unreachable (forbidden_roots() only keeps existing
  directories and realpath normalises their case), but an allowlist root that
  does not exist yet was rejected. Both sides are normcased now.
- New administrator allowlist, read from ra_config.json in the node directory
  (csv_allowed_roots / db_allowed_roots). No environment variable is read:
  reading one would add a python_environment_manipulation finding to the
  Registry scan, and the package is already flagged for the five existing
  reads. The file is absent by default, which keeps the current blacklist
  behaviour.
- The allowlist only narrows. Passing it still has to clear the UNC rejection
  and the forbidden-root loop. It is checked after _canonicalize() and before
  is_path_guard_disabled(), so "allowlist plus escape hatch" fails closed
  instead of the escape hatch silently winning.
- Invalid configuration fails closed with an actionable message: bad JSON,
  non-object top level, empty or missing lists, non-string roots, relative
  roots and bare drive letters are all rejected.
- for_write is no longer a dead parameter: it selects db_allowed_roots over
  csv_allowed_roots, so the two kinds stay separate.
- Node-directory data files are exempt: the bundled default CSV/DB are
  trusted runtime resources, and users sometimes write the full default path
  into custom_csv_path. Node source files are still blocked.

TOCTOU is unchanged and not claimed: check_db_path validates once and
sqlite3 reopens by path, and sqlite3 has no fd parameter.
2026-10-28 20:48:04 +08:00
StarAsh042 425a727708 chore(release): 5.1.6(扫描触发点二轮消除 + 发布卫生回归 + tests/docs 本地独享)
- db.py _write_schema_version:INSERT 语句提取为局部变量,
  断掉 database_operations 模式命中的 .execute( + 换行 + "INSERT INTO
  多行排版(SQL 与参数不变)
- paths.py:4 处系统目录探测 os.environ.get() → os.getenv();
  db.py 注释与 paths.py docstring 清除 sqlite3.connect() 字样(纵深防御)
- tests/test_publish_hygiene.py:发布包构成回归测试(本地测试套件新增),
  本次即靠它抓到 .comfyignore 无锚定 docs/ 误伤 web/docs/ 的真 bug,
  .comfyignore/.gitignore 均已改根锚定写法
- tests/ 与 docs/ 取消 git 跟踪转本地独享(.gitignore + .comfyignore),
  ci.yml test job 检出无 tests/ 时跳过而非失败
2026-10-26 00:07:43 +08:00
StarAsh042 b8506ebfea fix(registry): 等价 API 替换消除扫描误报(sqlite3.connect→sqlite3.Connection、os.environ.get→os.getenv)
- 行为零变化:338 个测试用例全过,门禁四件套全绿
- 目标:消除 Registry 安全扫描对 5.0.0-5.1.2 的 info 级误报 Flagged
- 兜底:如扫描器仍有其他触发模式,回退 registry-backend 人工申诉(稿已备)
2026-10-25 21:23:28 +08:00
StarAsh042 8e27b3dfc6 feat(security): 路径防护与受保护目录
自定义 CSV / 数据库路径原样透传等于把任意读写交给工作流作者。
命中系统目录、凭据目录、ComfyUI 自身代码或其它节点目录时直接拒绝,
并规范化 Windows 扩展前缀、ADS 与 UNC 管理共享写法。
2026-10-13 09:12:00 +08:00