96 lines
3.6 KiB
Go
96 lines
3.6 KiB
Go
package domain
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestAuthenticatedCursorRoundTrip_HP_CTL_06(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
codec, err := NewCursorCodec(bytes.Repeat([]byte{0x42}, 32))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
filters := HashCursorFilters([]byte("client=host-1\x00streams=stdout"))
|
|
want := Cursor{Kind: CursorKindOutput, FilterHash: filters, Position: []byte("uuid/event/offset"), SnapshotBoundary: []byte("upper-event")}
|
|
token, err := codec.Encode(want)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := codec.Decode(token, CursorKindOutput, filters)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Kind != want.Kind || got.FilterHash != want.FilterHash || !bytes.Equal(got.Position, want.Position) || !bytes.Equal(got.SnapshotBoundary, want.SnapshotBoundary) {
|
|
t.Fatalf("decoded cursor = %+v, want %+v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestCursorForgeryAndFilterBinding_BH_CTL_01(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
codec, _ := NewCursorCodec(bytes.Repeat([]byte{0x42}, 32))
|
|
filters := HashCursorFilters([]byte("client=one"))
|
|
token, _ := codec.Encode(Cursor{Kind: CursorKindCommands, FilterHash: filters, Position: []byte("position"), SnapshotBoundary: []byte("boundary")})
|
|
forged := []byte(token)
|
|
forged[len(forged)/2] ^= 1
|
|
if _, err := codec.Decode(string(forged), CursorKindCommands, filters); !errors.Is(err, ErrInvalidCursor) {
|
|
t.Fatalf("forged cursor error = %v", err)
|
|
}
|
|
otherFilters := HashCursorFilters([]byte("client=two"))
|
|
if _, err := codec.Decode(token, CursorKindCommands, otherFilters); !errors.Is(err, ErrCursorFilterMismatch) {
|
|
t.Fatalf("filter mismatch error = %v", err)
|
|
}
|
|
if _, err := codec.Decode(token, CursorKindOutput, filters); !errors.Is(err, ErrInvalidCursor) {
|
|
t.Fatalf("kind mismatch error = %v", err)
|
|
}
|
|
for _, malformed := range []string{"", "***", strings.Repeat("a", 4096)} {
|
|
if _, err := codec.Decode(malformed, CursorKindCommands, filters); !errors.Is(err, ErrInvalidCursor) {
|
|
t.Errorf("malformed cursor %q error = %v", malformed[:min(len(malformed), 16)], err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCursorInputBounds_BH_CTL_01(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if _, err := NewCursorCodec([]byte("short")); !errors.Is(err, ErrInvalidCursor) {
|
|
t.Fatalf("short key error = %v", err)
|
|
}
|
|
codec, _ := NewCursorCodec(bytes.Repeat([]byte{1}, 32))
|
|
filter := HashCursorFilters(nil)
|
|
for _, cursor := range []Cursor{
|
|
{Kind: 0, FilterHash: filter, Position: []byte("x"), SnapshotBoundary: []byte("y")},
|
|
{Kind: CursorKindCommands, FilterHash: filter, SnapshotBoundary: []byte("y")},
|
|
{Kind: CursorKindCommands, FilterHash: filter, Position: bytes.Repeat([]byte("x"), maxCursorFieldBytes+1), SnapshotBoundary: []byte("y")},
|
|
} {
|
|
if _, err := codec.Encode(cursor); !errors.Is(err, ErrInvalidCursor) {
|
|
t.Errorf("invalid cursor error = %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// FuzzDecodeCursorBounded_SEC_CTL_02 exercises the token boundary shared by
|
|
// every cursor-resumable control read. Decode must reject malformed or forged
|
|
// input without panicking or allocating past its documented token ceiling.
|
|
func FuzzDecodeCursorBounded_SEC_CTL_02(f *testing.F) {
|
|
codec, err := NewCursorCodec(bytes.Repeat([]byte{0x42}, 32))
|
|
if err != nil {
|
|
f.Fatal(err)
|
|
}
|
|
filters := HashCursorFilters([]byte("client=host-1\x00streams=stdout"))
|
|
valid, err := codec.Encode(Cursor{Kind: CursorKindOutput, FilterHash: filters, Position: []byte("event/offset"), SnapshotBoundary: []byte("upper-event")})
|
|
if err != nil {
|
|
f.Fatal(err)
|
|
}
|
|
for _, seed := range []string{"", "***", valid, strings.Repeat("a", 4096)} {
|
|
f.Add(seed)
|
|
}
|
|
f.Fuzz(func(t *testing.T, token string) {
|
|
_, _ = codec.Decode(token, CursorKindOutput, filters)
|
|
})
|
|
}
|