Skip to content

Add pluggable Logon authentication (FixLogon) for the FIX adapter - #418

Open
0-jake-0 wants to merge 1 commit into
mainfrom
claude/fix-venue-adapter-kes-ugxsko
Open

Add pluggable Logon authentication (FixLogon) for the FIX adapter#418
0-jake-0 wants to merge 1 commit into
mainfrom
claude/fix-venue-adapter-kes-ugxsko

Conversation

@0-jake-0

@0-jake-0 0-jake-0 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends the FIX adapter so a caller can supply a custom Logon authentication scheme, not just Username/Password. Adds a FixLogon enum and a LogonContext, letting a venue attach a cryptographic signature (e.g. Ed25519) bound to the exact Logon bytes on the wire. wingfoil itself stays venue/crypto-agnostic.

Changes

  • FixLogonNone / Password(String) / Custom(Arc<dyn Fn(&LogonContext) -> Vec<(u32, String)>>).
  • LogonContext — exposes MsgType, SenderCompID, TargetCompID, MsgSeqNum, and the exact SendingTime string the Logon will carry, so a signer computes its payload over the canonical wire format.
  • FixSession::send_with — computes the sequence number and SendingTime once and hands both to the field builder and the encoder, preventing skew between signature and wire bytes. SendingTime now has millisecond precision.
  • fix_connect_tls_logon — new public factory taking a FixLogon; fix_connect_tls(password: Option<&str>) is unchanged and delegates to it via FixLogon::from.
  • Docs in the module header and CLAUDE.md.

Notes

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q96qpjaqcpywW3rdy1eHjW


Generated by Claude Code

The FIX adapter only supported LMAX-style Username/Password (tags 553/554)
in the Logon message. Venues like Binance authenticate with a signature
computed over the Logon header, which the fixed encoder couldn't express.

Add a generic `FixLogon` (None / Password / Custom) plus a `LogonContext`
carrying the SenderCompID, TargetCompID, MsgSeqNum and the exact SendingTime
string the Logon will carry. `FixSession::send_with` now computes the sequence
number and SendingTime once and hands both to the field builder and the
encoder, so a signer signs exactly what goes on the wire. SendingTime gains
millisecond precision.

`fix_connect_tls` is unchanged (delegates to a new `fix_connect_tls_logon`
that takes a `FixLogon`). wingfoil stays free of any venue/crypto specifics —
the Ed25519 signer lives in the caller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q96qpjaqcpywW3rdy1eHjW
0-jake-0 added a commit that referenced this pull request Jul 8, 2026
* fix: pluggable Logon authentication (FixLogon) for the FIX adapter

The FIX adapter only supported LMAX-style Username/Password (tags 553/554)
in the Logon message. Venues like Binance authenticate with a signature
computed over the Logon header, which the fixed encoder couldn't express.

Add a generic `FixLogon` (None / Password / Custom) plus a `LogonContext`
carrying the SenderCompID, TargetCompID, MsgSeqNum and the exact SendingTime
string the Logon will carry. `FixSession::send_with` now computes the sequence
number and SendingTime once and hands both to the field builder and the
encoder, so a signer signs exactly what goes on the wire. SendingTime gains
millisecond precision.

`fix_connect_tls` is unchanged (delegates to a new `fix_connect_tls_logon`
that takes a `FixLogon`). wingfoil stays free of any venue/crypto specifics —
the Ed25519 signer lives in the caller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q96qpjaqcpywW3rdy1eHjW

* Address PR #418 review: password test, hot-path alloc, naming, docs

- Add password_logon_sends_username_and_password test guarding the
  FixLogon::Password path (tags 553/554) after the send_with refactor.
- Avoid a per-message Vec/String clone on the send hot path: extract a
  shared write_encoded core so send() frames directly from the borrowed
  slice instead of round-tripping through send_with's builder.
- Rename TAG_RESET_ON_LOGON -> TAG_RESET_SEQ_NUM_FLAG to match tag 141's
  real name (ResetSeqNumFlag), aligning the constant with its comment.
- Note RawDataLength (tag 95) precedes RawData (tag 96) in the module and
  fix_connect_tls_logon docs, consistent with CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vum2BQHuMNkRUr8Wk1VVrp

* Fix flaky zmq_first_message_not_dropped_no_delay: keep buffer once accepted

The ZMQ publisher buffers messages until a subscriber connects (slow-joiner
mitigation) and clears the buffer after BUFFER_TIMEOUT so a late subscriber
doesn't receive stale backlog. The clear fired purely on wall-clock buffer
age, even in the same cycle where check_monitor() had just observed the TCP
ACCEPTED event but subscriber_connected was not yet set (still inside the
~50ms subscription-propagation wait).

Under parallel CI load the publisher's graph cycles can be starved past
BUFFER_TIMEOUT; the delayed cycle then observes the accept and immediately
discards the buffer, dropping message 1 — the exact invariant the test
asserts.

Only clear the buffer while no subscriber has begun connecting
(accepted_at.is_none()). Once an accept is observed we are committed to
flushing to that subscriber. The anti-unbounded-growth guarantee is
preserved: with no subscriber, accepted_at stays None and the buffer still
clears every BUFFER_TIMEOUT.

Verified: zmq integration suite green, and the previously-flaky test passes
20/20 under repeated runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vum2BQHuMNkRUr8Wk1VVrp

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants