Skip to content

Commit

Permalink
fix: make inmem bookmarks random for each run
Browse files Browse the repository at this point in the history
As inmem storage is not persisted, make sure watch bookmark from one run
doesn't work with another run.

This still allows watches to be restarted on connection failures, but if
the watch is restarted on a program restart, bookmark won't match
anymore.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
  • Loading branch information
smira committed Nov 5, 2024
1 parent 5eca531 commit 19c9236
Showing 1 changed file with 23 additions and 3 deletions.
26 changes: 23 additions & 3 deletions pkg/state/impl/inmem/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ package inmem

import (
"context"
"crypto/rand"
"encoding/binary"
"fmt"
"io"
"slices"
"sort"
"sync"
Expand Down Expand Up @@ -265,16 +267,34 @@ func (collection *ResourceCollection) Destroy(ctx context.Context, ptr resource.
return nil
}

// bookmarkCookie is a random cookie used to encode bookmarks.
//
// As the state is in-memory, we need to distinguish between bookmarks from different runs of the program.
var bookmarkCookie = sync.OnceValue(func() []byte {
cookie := make([]byte, 8)

_, err := io.ReadFull(rand.Reader, cookie)
if err != nil {
panic(err)
}

return cookie
})

func encodeBookmark(pos int64) state.Bookmark {
return binary.BigEndian.AppendUint64(nil, uint64(pos))
return binary.BigEndian.AppendUint64(slices.Clone(bookmarkCookie()), uint64(pos))
}

func decodeBookmark(bookmark state.Bookmark) (int64, error) {
if len(bookmark) != 8 {
if len(bookmark) != 16 {
return 0, fmt.Errorf("invalid bookmark length: %d", len(bookmark))
}

return int64(binary.BigEndian.Uint64(bookmark)), nil
if !slices.Equal(bookmark[:8], bookmarkCookie()) {
return 0, fmt.Errorf("invalid bookmark cookie")
}

return int64(binary.BigEndian.Uint64(bookmark[8:])), nil
}

// Watch for specific resource changes.
Expand Down

0 comments on commit 19c9236

Please sign in to comment.