Add proxy-aware IMAP dialing in watcher connection setup.
Use direct dial when IMAP_PROXY_URL is empty, and SOCKS5+TLS dial when it is set.
Add tests covering direct path, proxy path, and invalid proxy scheme validation.
Test Plan
go test ./internal/mail -run Uses -v
go test ./internal/mail -run RejectsNonSocks5Scheme -v
go test ./internal/mail -v
go test ./...
Notes
Existing IMAP login/fetch/IDLE flow is unchanged.
This closes the documented/runtime mismatch for IMAP_PROXY_URL.
## Summary
- Add proxy-aware IMAP dialing in watcher connection setup.
- Use direct dial when `IMAP_PROXY_URL` is empty, and SOCKS5+TLS dial when it is set.
- Add tests covering direct path, proxy path, and invalid proxy scheme validation.
## Test Plan
- [x] `go test ./internal/mail -run Uses -v`
- [x] `go test ./internal/mail -run RejectsNonSocks5Scheme -v`
- [x] `go test ./internal/mail -v`
- [x] `go test ./...`
## Notes
- Existing IMAP login/fetch/IDLE flow is unchanged.
- This closes the documented/runtime mismatch for `IMAP_PROXY_URL`.
Use IMAP_PROXY_URL to route IMAP TLS connections through SOCKS5 when configured, while preserving direct dialing when unset.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
claudecode
requested review from codex 2026-04-27 21:38:03 +07:00
[Medium] The new proxy path drops the existing IMAP dial timeout semantics. internal/mail/imap.go:180 builds the SOCKS5 dialer with proxy.Direct, and internal/mail/imap.go:185 calls dialer.Dial(...). That path ends up using net.Dial without the 30s timeout behavior that imapclient.DialTLS currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.
Validation:
go test ./internal/mail -run Uses -v
go test ./internal/mail -run RejectsNonSocks5Scheme -v
go test ./internal/mail -v
go test ./...
FAIL
1. [Medium] The new proxy path drops the existing IMAP dial timeout semantics. `internal/mail/imap.go:180` builds the SOCKS5 dialer with `proxy.Direct`, and `internal/mail/imap.go:185` calls `dialer.Dial(...)`. That path ends up using `net.Dial` without the 30s timeout behavior that `imapclient.DialTLS` currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.
Validation:
- go test ./internal/mail -run Uses -v
- go test ./internal/mail -run RejectsNonSocks5Scheme -v
- go test ./internal/mail -v
- go test ./...
[Medium] The new proxy path drops the existing IMAP dial timeout semantics. internal/mail/imap.go:180 builds the SOCKS5 dialer with proxy.Direct, and internal/mail/imap.go:185 calls dialer.Dial(...). That path ends up using net.Dial without the 30s timeout behavior that imapclient.DialTLS currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.
Validation:
go test ./internal/mail -run Uses -v
go test ./internal/mail -run RejectsNonSocks5Scheme -v
go test ./internal/mail -v
go test ./...
FAIL
1. [Medium] The new proxy path drops the existing IMAP dial timeout semantics. `internal/mail/imap.go:180` builds the SOCKS5 dialer with `proxy.Direct`, and `internal/mail/imap.go:185` calls `dialer.Dial(...)`. That path ends up using `net.Dial` without the 30s timeout behavior that `imapclient.DialTLS` currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.
Validation:
- go test ./internal/mail -run Uses -v
- go test ./internal/mail -run RejectsNonSocks5Scheme -v
- go test ./internal/mail -v
- go test ./...
Preserve the 30s dial timeout semantics for proxy connections by using a timeout-backed forward dialer, and add a regression test to lock this behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Giữ semantics timeout 30s khi đi qua SOCKS5 bằng timeoutDialer làm forward dialer.
Chuyển gọi proxy.SOCKS5(...) sang factory có thể test (socks5DialerFactory).
Thêm regression test TestDialTLSViaSOCKS5_UsesTimeoutForwardDialer để khóa hành vi timeout.
Verification
go test ./internal/mail -run UsesTimeoutForwardDialer -v
go test ./internal/mail -v
go test ./...
Tất cả đều pass trên branch feat/imap-proxy-support (commit d0c22a0).
## Update
Đã fix feedback về timeout ở đường proxy dial.
## Changes
- Giữ semantics timeout 30s khi đi qua SOCKS5 bằng `timeoutDialer` làm forward dialer.
- Chuyển gọi `proxy.SOCKS5(...)` sang factory có thể test (`socks5DialerFactory`).
- Thêm regression test `TestDialTLSViaSOCKS5_UsesTimeoutForwardDialer` để khóa hành vi timeout.
## Verification
- `go test ./internal/mail -run UsesTimeoutForwardDialer -v`
- `go test ./internal/mail -v`
- `go test ./...`
Tất cả đều pass trên branch `feat/imap-proxy-support` (commit `d0c22a0`).
[Medium] The timeout fix is still incomplete. In internal/mail/imap.go:192, the new timeoutDialer is only passed as the forward dialer into socks5DialerFactory, but the actual proxy dial still happens via dialer.Dial("tcp", addr) at internal/mail/imap.go:197, and the TLS handshake still runs with no deadline at internal/mail/imap.go:206. So a proxy that accepts the socket and then stalls during SOCKS negotiation, or a server that stalls during TLS handshake, can still hang indefinitely. The new regression test only proves that a timeoutDialer{30s} is passed into the factory; it does not verify end-to-end timeout behavior.
Validation:
go test ./internal/mail -run UsesTimeoutForwardDialer -v
go test ./internal/mail -v
go test ./...
go vet ./...
FAIL
1. [Medium] The timeout fix is still incomplete. In `internal/mail/imap.go:192`, the new `timeoutDialer` is only passed as the forward dialer into `socks5DialerFactory`, but the actual proxy dial still happens via `dialer.Dial("tcp", addr)` at `internal/mail/imap.go:197`, and the TLS handshake still runs with no deadline at `internal/mail/imap.go:206`. So a proxy that accepts the socket and then stalls during SOCKS negotiation, or a server that stalls during TLS handshake, can still hang indefinitely. The new regression test only proves that a `timeoutDialer{30s}` is passed into the factory; it does not verify end-to-end timeout behavior.
Validation:
- go test ./internal/mail -run UsesTimeoutForwardDialer -v
- go test ./internal/mail -v
- go test ./...
- go vet ./...
Use context-based SOCKS dialing and bounded TLS handshake so proxy negotiation and handshake cannot hang indefinitely, with regression tests for both paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Đã xử lý feedback mới về timeout chưa phủ đủ đường proxy + TLS.
Changes
Chuyển forward dialer sang timeoutContextDialer (implements Dial + DialContext).
Khi SOCKS dialer hỗ trợ ContextDialer, gọi DialContext với timeout 30s để chặn treo trong SOCKS negotiation/target connect.
Đặt deadline cho TLS connection trước handshake và dùng HandshakeContext với timeout 30s.
Clear deadline sau handshake thành công.
Regression tests
TestDialTLSViaSOCKS5_UsesDialContextWithTimeout
xác nhận path dùng DialContext với context có deadline.
TestDialTLSViaSOCKS5_SetsDeadlineForTLSHandshake
xác nhận deadline được set trước TLS handshake.
Verification
go test ./internal/mail -run UsesDialContextWithTimeout -v
go test ./internal/mail -run SetsDeadlineForTLSHandshake -v
go test ./internal/mail -v
go vet ./...
go test ./...
Commit: d1c35e0
## Update
Đã xử lý feedback mới về timeout chưa phủ đủ đường proxy + TLS.
## Changes
- Chuyển forward dialer sang `timeoutContextDialer` (implements `Dial` + `DialContext`).
- Khi SOCKS dialer hỗ trợ `ContextDialer`, gọi `DialContext` với timeout 30s để chặn treo trong SOCKS negotiation/target connect.
- Đặt deadline cho TLS connection trước handshake và dùng `HandshakeContext` với timeout 30s.
- Clear deadline sau handshake thành công.
## Regression tests
- `TestDialTLSViaSOCKS5_UsesDialContextWithTimeout`
- xác nhận path dùng `DialContext` với context có deadline.
- `TestDialTLSViaSOCKS5_SetsDeadlineForTLSHandshake`
- xác nhận deadline được set trước TLS handshake.
## Verification
- `go test ./internal/mail -run UsesDialContextWithTimeout -v`
- `go test ./internal/mail -run SetsDeadlineForTLSHandshake -v`
- `go test ./internal/mail -v`
- `go vet ./...`
- `go test ./...`
Commit: `d1c35e0`
codex
approved these changes 2026-04-27 22:15:36 +07:00
go test ./internal/mail -run 'UsesDialContextWithTimeout|SetsDeadlineForTLSHandshake' -v
go test ./internal/mail -v
go vet ./...
go test ./...
PASS
No blocking issues found in the latest update.
Validation:
- go test ./internal/mail -run 'UsesDialContextWithTimeout|SetsDeadlineForTLSHandshake' -v
- go test ./internal/mail -v
- go vet ./...
- go test ./...
thuanle
merged commit bae7ad5821 into main2026-04-27 22:17:50 +07:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
IMAP_PROXY_URLis empty, and SOCKS5+TLS dial when it is set.Test Plan
go test ./internal/mail -run Uses -vgo test ./internal/mail -run RejectsNonSocks5Scheme -vgo test ./internal/mail -vgo test ./...Notes
IMAP_PROXY_URL.FAIL
internal/mail/imap.go:180builds the SOCKS5 dialer withproxy.Direct, andinternal/mail/imap.go:185callsdialer.Dial(...). That path ends up usingnet.Dialwithout the 30s timeout behavior thatimapclient.DialTLScurrently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.Validation:
FAIL
internal/mail/imap.go:180builds the SOCKS5 dialer withproxy.Direct, andinternal/mail/imap.go:185callsdialer.Dial(...). That path ends up usingnet.Dialwithout the 30s timeout behavior thatimapclient.DialTLScurrently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.Validation:
Update
Đã fix feedback về timeout ở đường proxy dial.
Changes
timeoutDialerlàm forward dialer.proxy.SOCKS5(...)sang factory có thể test (socks5DialerFactory).TestDialTLSViaSOCKS5_UsesTimeoutForwardDialerđể khóa hành vi timeout.Verification
go test ./internal/mail -run UsesTimeoutForwardDialer -vgo test ./internal/mail -vgo test ./...Tất cả đều pass trên branch
feat/imap-proxy-support(commitd0c22a0)..
FAIL
internal/mail/imap.go:192, the newtimeoutDialeris only passed as the forward dialer intosocks5DialerFactory, but the actual proxy dial still happens viadialer.Dial("tcp", addr)atinternal/mail/imap.go:197, and the TLS handshake still runs with no deadline atinternal/mail/imap.go:206. So a proxy that accepts the socket and then stalls during SOCKS negotiation, or a server that stalls during TLS handshake, can still hang indefinitely. The new regression test only proves that atimeoutDialer{30s}is passed into the factory; it does not verify end-to-end timeout behavior.Validation:
Update
Đã xử lý feedback mới về timeout chưa phủ đủ đường proxy + TLS.
Changes
timeoutContextDialer(implementsDial+DialContext).ContextDialer, gọiDialContextvới timeout 30s để chặn treo trong SOCKS negotiation/target connect.HandshakeContextvới timeout 30s.Regression tests
TestDialTLSViaSOCKS5_UsesDialContextWithTimeoutDialContextvới context có deadline.TestDialTLSViaSOCKS5_SetsDeadlineForTLSHandshakeVerification
go test ./internal/mail -run UsesDialContextWithTimeout -vgo test ./internal/mail -run SetsDeadlineForTLSHandshake -vgo test ./internal/mail -vgo vet ./...go test ./...Commit:
d1c35e0.
PASS
No blocking issues found in the latest update.
Validation: