Both helpers in factories/file_factory/message_files.py are only invoked
from replay paths that intentionally skip re-validation, so the config
argument was always None. Remove it from the signatures and update the
two call sites; module docstring records the design intent.
The walrus filter was redundant given the early return on empty input:
empty whitelist entries normalize to "" and can never match a non-empty
input extension, and empty input is already rejected upfront.
A whitelist with an empty / whitespace entry (e.g. a stray comma in DSL)
combined with an extensionless file would spuriously match — both sides
normalize to "" and pass. Filter empty normalized whitelist entries and
short-circuit when the input extension itself normalizes to empty, so
invalid whitelist entries can't widen the allowlist.
Reported by Copilot on PR review.
Follow-up to the prior fix. The bucket-semantics rewrite changed the
extension-whitelist guard from `is not None` to truthiness, which
silently widened behavior for the empty-list case (UI never submits it,
but DSL / API paths could). Restore the original deny-on-empty
posture: when a file falls into the CUSTOM bucket, an explicitly set
whitelist (including []) is authoritative.
Also tightens _normalize_extension so whitespace-only input returns ""
consistent with empty input, and locks two contracts with tests:
- empty whitelist + CUSTOM bucket rejects (regression guard for the
silent widening)
- TokenBufferMemory passes config=None to build_from_message_file
(regression guard for the replay-skips-validation contract)
A Chatflow file uploaded into the CUSTOM type slot is coerced to its
detected type by _resolve_file_type (PNG -> IMAGE), and MessageFile.type
persists that resolved type. On history replay, build_from_message_file
rebuilds mapping["type"] from MessageFile.type, so a file that passed
round 1 (mapping["type"]=="custom") was rejected on round 2
(mapping["type"]=="image") even though the workflow config was unchanged.
- Refactor is_file_valid_with_config with bucket semantics: CUSTOM acts
as a fallback bucket gated by allowed_file_extensions, compared case-
and dot-insensitively. This also fixes a parallel mismatch where a
user whitelist of [".PNG", "png", "JPG", ...] failed to match the
upload-side ".png" (always lowercase with leading dot).
- Skip re-validation when rehydrating files from conversation history in
TokenBufferMemory and BaseAgentRunner; history files were validated at
upload time, mirroring build_file_from_stored_mapping.
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>