lau0708 8712d495e2
fix(channels): grant sandbox read bits to Feishu/DingTalk inbound uploads (#5998)
The channel manager persists inbound attachments with
`write_upload_file_no_symlink` (root-owned, mode 0o600) and then relaxes them
to group/other readable via `_make_inbound_file_sandbox_readable`. In
AIO/Docker sandbox mode the sandbox runs as a non-root user on the bind-mounted
thread directory, so without those bits the file is unreadable and the agent
sees an empty attachment. The HTTP upload route applies the same permit.

`FeishuChannel._receive_single_file` and `DingTalkChannel._receive_single_file`
persist their own bytes and hand back a virtual path instead of routing content
through the manager, so neither reached that permit:

- Feishu leaves `msg.files` populated with `file_key` descriptors, but the
  manager's `_read_http_inbound_file` requires a `url` key, so its ingest pass
  reads no data and skips the upload.
- DingTalk clears `msg.files`, so the ingest pass returns immediately.

Telegram is unaffected because it hands raw bytes to the manager through
`INBOUND_FILE_CONTENT_KEY`, which is why it was covered when the permit was
added. Apply `apply_upload_sandbox_permits(..., S_IRGRP | S_IROTH)` right after
each channel's own write, off the event loop, mirroring the manager and HTTP
paths.

Tests: `test_channel_file_attachments.py` gains a mounted-provider regression
per channel asserting the persisted upload is group/other readable.
2026-09-28 22:19:32 +08:00
..