carlos / platform Public

genselect: verify any root's header, assert MaxLevel0TXID (Plan 7b review round 1)

Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 574d946998b304571d69c7ead5c38581875d6838 parent 866ec8f
2 files changed, +105 −0
  • internal/genselect/select.go +3 −0
  • internal/genselect/select_test.go +102 −0

CI passed — run details

diff --git a/internal/genselect/select.go b/internal/genselect/select.go
index e956f8c67..0a9c21368 100644
--- a/internal/genselect/select.go
+++ b/internal/genselect/select.go
@@ -389,6 +389,9 @@ func selectFiles(ctx context.Context, s Reader, bucket, base string, versions []
break
}
if p.Root == nil {
+ if err := checkRoot(ctx, s, bucket, *best, false); err != nil {
+ return nil, err
+ }
cp := *best
p.Root = &cp
}
diff --git a/internal/genselect/select_test.go b/internal/genselect/select_test.go
index 3552a892c..82ea7a8c6 100644
--- a/internal/genselect/select_test.go
+++ b/internal/genselect/select_test.go
@@ -301,6 +301,108 @@ func TestRefusals(t *testing.T) {
}
}
+func TestContinuationRootRefusals(t *testing.T) {
+ for _, gen := range []string{"", "fresh"} {
+ name := gen
+ if name == "" {
+ name = "origin"
+ }
+ for level := 0; level < 9; level++ {
+ for _, corruption := range []string{"malformed_header", "truncated_file", "header_range_mismatch"} {
+ t.Run(fmt.Sprintf("%s/level_%d/%s", name, level, corruption), func(t *testing.T) {
+ f := newFixture(t)
+ if gen == "" {
+ f.origin()
+ } else {
+ f.marker.Op = gen
+ f.marker.Pin = Pin{}
+ f.req.Holder.Generation = gen
+ f.publish()
+ }
+ root := f.file(gen, level, 1, 1)
+ body := header(t, 1, 1)
+ switch corruption {
+ case "malformed_header":
+ body[0] ^= 0xff
+ case "truncated_file":
+ body = body[:len(body)-1]
+ case "header_range_mismatch":
+ body = header(t, 1, 2)
+ }
+ f.b.Put("data", root.Key, body)
+ before := f.b.Snapshot()
+ got, err := Select(t.Context(), f.store, f.req)
+ if got != nil || !errors.Is(err, ErrRoot) {
+ t.Fatalf("got %+v / %v, want nil / %v", got, err, ErrRoot)
+ }
+ if f.b.Snapshot() != before {
+ t.Fatal("selection mutated storage")
+ }
+ })
+ }
+ }
+ }
+}
+
+func TestMaxLevel0TXID(t *testing.T) {
+ tests := []struct {
+ name string
+ setup func(*fixture)
+ wantLevel0 uint64
+ wantRestored uint64
+ }{
+ {"current_anchor", func(f *fixture) {}, 11, 11},
+ {"current_continuation", func(f *fixture) {
+ f.file("g0", 0, 12, 12)
+ f.file("g0", 0, 13, 13)
+ }, 13, 13},
+ {"noncurrent_data", func(f *fixture) {
+ old := f.file("g0", 0, 30, 30)
+ f.b.BareDelete("data", old.Key)
+ }, 11, 11},
+ {"delete_marker_only", func(f *fixture) {
+ old := f.file("g0", 0, 40, 40)
+ f.b.BareDelete("data", old.Key)
+ if err := f.b.DeleteVersion(f.t.Context(), "data", old.Key, old.VersionID); err != nil {
+ f.t.Fatal(err)
+ }
+ }, 11, 11},
+ {"newer_restored_snapshot", func(f *fixture) {
+ f.file("g0", 9, 1, 30)
+ }, 11, 30},
+ {"no_current_level0", func(f *fixture) {
+ anchor := f.file("g0", 0, 11, 11)
+ f.b.BareDelete("data", anchor.Key)
+ }, 0, 11},
+ }
+ for _, entry := range []string{"ordinary", "prepared"} {
+ for _, tt := range tests {
+ t.Run(entry+"/"+tt.name, func(t *testing.T) {
+ f := newFixture(t)
+ tt.setup(f)
+ var got *Plan
+ var err error
+ if entry == "ordinary" {
+ got, err = Select(t.Context(), f.store, f.req)
+ } else {
+ p := f.marker.Pin
+ got, err = SelectPrepared(t.Context(), f.store, f.req, PreparedPin{
+ Generation: "g0", SnapshotKey: p.SnapshotKey, SnapshotVersion: p.SnapshotVersion,
+ SnapshotTXID: p.SnapshotTXID, SnapshotCRC64: p.SnapshotCRC64,
+ })
+ }
+ if err != nil || got == nil {
+ t.Fatalf("got %+v / %v, want a plan", got, err)
+ }
+ if got.MaxLevel0TXID != tt.wantLevel0 || got.MaxTXID != tt.wantRestored {
+ t.Fatalf("MaxLevel0TXID=%d, MaxTXID=%d; want %d, %d",
+ got.MaxLevel0TXID, got.MaxTXID, tt.wantLevel0, tt.wantRestored)
+ }
+ })
+ }
+ }
+}
+
func alterVersion(f *fixture, id string) {
f.file("g0", 0, 12, 12)
f.store = altered{Reader: f.b, list: func(vs []lease.ObjectVersion) ([]lease.ObjectVersion, error) {