feat: send canonical client command events
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1"
|
||||||
|
"github.com/rvbox/rvbox/internal/agentproto"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendCommandEvent writes a previously durable, sequence-assigned event. It
|
||||||
|
// derives the immutable digest at the final wire boundary so retrying the same
|
||||||
|
// event produces byte-equivalent protocol evidence.
|
||||||
|
func SendCommandEvent(ctx context.Context, transport Transport, session Session, event *rvboxv1.CommandEvent, limits agentproto.Limits) error {
|
||||||
|
if transport == nil || event == nil || session.ID == "" || session.Generation == 0 {
|
||||||
|
return ErrProtocolHandshake
|
||||||
|
}
|
||||||
|
copyEvent := proto.Clone(event).(*rvboxv1.CommandEvent)
|
||||||
|
digest, err := agentproto.CommandEventDigest(copyEvent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
copyEvent.ImmutableEventSha256 = digest[:]
|
||||||
|
envelope := &rvboxv1.AgentEnvelope{SessionId: session.ID, SessionGeneration: session.Generation, Payload: &rvboxv1.AgentEnvelope_CommandEvent{CommandEvent: copyEvent}}
|
||||||
|
if err := agentproto.ValidateEnvelope(envelope, limits, rvboxv1.Platform_PLATFORM_WINDOWS); err != nil {
|
||||||
|
return fmt.Errorf("validate command event: %w", err)
|
||||||
|
}
|
||||||
|
encoded, err := proto.Marshal(envelope)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return transport.Write(ctx, encoded)
|
||||||
|
}
|
||||||
@@ -101,6 +101,23 @@ func TestPersistDispatchUsesImmutableHash_HP_DISPATCH_04(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendCommandEventCanonicalDigest_HP_EVENT_02(t *testing.T) {
|
||||||
|
transport := &fakeTransport{}
|
||||||
|
event := &rvboxv1.CommandEvent{IssueUuid: "019c46f1-1d02-7000-8000-000000000065", EventSeq: 1, ObservedAt: timestamppb.Now(), Payload: &rvboxv1.CommandEvent_Lifecycle{Lifecycle: &rvboxv1.LifecycleChange{Lifecycle: rvboxv1.CommandLifecycle_COMMAND_RUNNING, CommandRevision: 1}}}
|
||||||
|
if err := SendCommandEvent(context.Background(), transport, Session{ID: "issued-session", Generation: 7}, event, agentproto.DefaultLimits()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var envelope rvboxv1.AgentEnvelope
|
||||||
|
if err := proto.Unmarshal(transport.written, &envelope); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sent := envelope.GetCommandEvent()
|
||||||
|
digest, err := agentproto.CommandEventDigest(sent)
|
||||||
|
if err != nil || sent == nil || string(digest[:]) != string(sent.GetImmutableEventSha256()) {
|
||||||
|
t.Fatalf("sent event = %#v, %v", sent, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type fakeTransport struct {
|
type fakeTransport struct {
|
||||||
written []byte
|
written []byte
|
||||||
read []byte
|
read []byte
|
||||||
|
|||||||
@@ -224,6 +224,12 @@ layer = "unit"
|
|||||||
status = "implemented"
|
status = "implemented"
|
||||||
tests = ["internal/server/session/agent_server_test.go:TestWireEventAppendCarriesClientBinding_HP_EVENT_01"]
|
tests = ["internal/server/session/agent_server_test.go:TestWireEventAppendCarriesClientBinding_HP_EVENT_01"]
|
||||||
|
|
||||||
|
[[requirements]]
|
||||||
|
id = "HP-EVENT-02"
|
||||||
|
layer = "unit"
|
||||||
|
status = "implemented"
|
||||||
|
tests = ["internal/client/agent/handshake_test.go:TestSendCommandEventCanonicalDigest_HP_EVENT_02"]
|
||||||
|
|
||||||
[[requirements]]
|
[[requirements]]
|
||||||
id = "HP-SES-05"
|
id = "HP-SES-05"
|
||||||
layer = "integration"
|
layer = "integration"
|
||||||
|
|||||||
Reference in New Issue
Block a user