5.5 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| raw-framing-interface-implementation | Implement RawFramingInterface accept/recv/send with first-frame auth | completed |
|
narrow | low | component | implementation |
Description
Implement RawFramingInterface and RawFramingSession to handle length-prefixed EventEnvelope frames over a byte stream, with first-frame authentication. Currently RawFramingInterface::accept() returns an error and RawFramingSession stubs exist.
Per the integration plan section 2.2 and interface.md:
RawFramingInterface: Reads 4-byte length-prefixed JSON EventEnvelope frames from a transport stream (TCP, TLS, iroh, etc.). No SSH wrapping — the raw framing interface carries call protocol events directly.
First-frame auth: The first InterfaceEvent on a RawFramingSession carries an auth token in the InterfaceEvent.identity field or a dedicated auth event type. After IdentityProvider::resolve_from_token() verifies the token and produces an Identity, the session is authenticated. Subsequent frames are call protocol EventEnvelope data. If auth fails, the session is terminated immediately.
Current state of the code:
RawFramingInterfaceaccepts anyTransportStreambut returns an errorRawFramingSessionis an empty struct with stubrecv()(returnsNone) andsend()(returns error)call::frame::{encode, decode, decode_with_remainder}already implement the wire formatIdentityProvider::resolve_from_token()exists but is not yet wired toAuthTokenverification (that's coming in the API keys task)
Implementation approach:
RawFramingInterface::accept()takes aTransportStream, wraps it in aBufReaderfor buffered reading, stores it inRawFramingSession. TheRawFramingSessionis created in an "unauthenticated" state.RawFramingSession::recv()reads frames from the stream:- If unauthenticated: read the first frame, extract the auth token, call
IdentityProvider::resolve_from_token(). On success, transition to "authenticated" with the resolvedIdentity. On failure, return an error (session terminated). - If authenticated: read
EventEnvelopeframes, wrap inInterfaceEvent::with_identity(envelope, identity).
- If unauthenticated: read the first frame, extract the auth token, call
RawFramingSession::send()writesEventEnvelopeframes to the stream usingcall::frame::encode.
The RawFramingSession needs:
- A
BufReader<Box<dyn TransportStream>>for reading framed data - A
Box<dyn TransportStream>(or WriteHalf) for writing framed data - An
Option<Identity>tracking auth state - A reference to
IdentityProviderfor token resolution - A buffer for partial frame reads (
decode_with_remainderpattern)
Acceptance Criteria
RawFramingInterface::accept()takes aTransportStreamandStreamInterfaceConfig::RawFramingconfig, creates aRawFramingSessionwrapping the streamRawFramingSessionholds a buffered reader and writer over the transport stream, an auth state (Option<Identity>), and a reference toIdentityProviderRawFramingSession::recv()reads length-prefixedEventEnvelopeframes from the stream usingcall::frame::decode_with_remainder- First-frame auth: the first
recv()call resolves the auth token viaIdentityProvider::resolve_from_token()and stores the resultingIdentity - Subsequent
recv()calls produceInterfaceEvent::with_identity(envelope, identity)using the authenticated identity - Auth failure terminates the session:
recv()returns an error result on bad tokens RawFramingSession::send()writesEventEnvelopeframes to the stream usingcall::frame::encode- Unit test:
RawFramingInterface::accept()succeeds with a valid stream - Unit test:
RawFramingSessionround-trips anEventEnvelopethroughsend()andrecv()(after mock auth) - Unit test: First-frame auth with a valid token transitions to authenticated state
- Unit test: First-frame auth with an invalid token returns an error
- Integration test:
RawFramingSessionover atokio::io::duplexstream (simulated TCP) sends and receives multiple frames
References
- docs/research/integration-plan.md — Phase 2.2
- docs/architecture/interface.md — RawFramingInterface, first-frame auth model
- crates/alknet-core/src/interface/raw_framing.rs — Current stubs
- crates/alknet-core/src/call/frame.rs — Frame encode/decode
- crates/alknet-core/src/auth/identity.rs — IdentityProvider, resolve_from_token
Notes
The frame format is already implemented and tested in
call::frame. This task is primarily about wiring the frame reader/writer to theInterfaceSessiontrait and adding first-frame auth logic.
Consider using
tokio::io::BufReaderfor buffered reading andtokio::io::BufWriterfor buffered writing. Thedecode_with_remainderfunction handles partial reads by returning how many bytes were consumed — the session needs to maintain a read buffer for reassembly.
The
RawFramingInterfaceconfig should include anArc<dyn IdentityProvider>for first-frame auth. This follows the same pattern asSshInterfaceConfig.
Summary
Implemented RawFramingInterface::accept() and RawFramingSession with first-frame auth. RawFramingConfig now has auth: Arc. RawFramingSession splits stream via tokio::io::split, recv() implements first-frame auth with AuthToken resolution via IdentityProvider::resolve_from_token(), send() encodes via call::frame::encode with buffered writes, read_frame() uses decode_with_remainder for partial reassembly. 7 new tests.