Validate checkpoint ID in RefName (reject malformed refs) · Entire
Validate checkpoint ID in RefName (reject malformed refs)
29e8f1f·
Soph·2w ago·8 files·+80 added/-26 removed
RefName previously returned refs/entire/checkpoints// for an empty/invalid checkpoint ID, and callers built on the convention that the ID was already validated. Make RefName return (plumbing.ReferenceName, error), erroring when the ID is empty or an unrecognized format, so a bad ID can't silently become a malformed ref that gets pushed/fetched/looked up. Store call sites (refBase/setRef/resolveRefMaybeFetch/GetCheckpointAuthor) and the explain-on-clone fetch propagate the error; tests use a mustRefName helper for known-valid IDs and add a RefName_RejectsInvalidID case.
Sessions
2bd3564e62ebView transcript
Changes
8
cmd/entire/cli
checkpoint
Mpushqueue_test.go+6/-6
Mrefs_naming.go+11/-2
Mrefs_naming_test.go+21/-2
Mrefs_store.go+18/-4
Mrefs_store_seam_test.go+1/-1
Mrefs_store_test.go+7/-7
13 unmodified lines
.Parallel() q := NewPushQueue(t.TempDir())
a := RefName("a1b2c3d4e5f6") b := RefName("b2c3d4e5f6a1") a := mustRefName(t, "a1b2c3d4e5f6") b := mustRefName(t, "b2c3d4e5f6a1")
// Empty queue drains to nothing. refs, err := q.Drain()
func TestPushQueue_DrainDedupes(t *testing.T) {
t.Parallel() q := NewPushQueue(t.TempDir()) a := RefName("a1b2c3d4e5f6") a := mustRefName(t, "a1b2c3d4e5f6")
require.NoError(t, q.Enqueue(a)) require.NoError(t, q.Enqueue(a))
}
func TestPushQueue_RemovePreservesLaterEntries(t *testing.T) {
t.Parallel() q := NewPushQueue(t.TempDir()) a := RefName("a1b2c3d4e5f6") b := RefName("b2c3d4e5f6a1") a := mustRefName(t, "a1b2c3d4e5f6") b := mustRefName(t, "b2c3d4e5f6a1")
// Simulate: drain sees [a], then b is enqueued during the push, then we // Remove(a). b must survive for the next pre-push. }
.Parallel() dir := t.TempDir() q := NewPushQueue(dir) a := RefName("a1b2c3d4e5f6") a := mustRefName(t, "a1b2c3d4e5f6") require.NoError(t, q.Enqueue(a))
// Append a garbage line + a blank line directly.
package checkpoint
import ( "fmt" "strings"
"github.com/go-git/go-git/v6/plumbing" )
// refs/entire/checkpoints/
// It errors on an empty or unrecognized checkpoint ID rather than returning a // malformed ref (e.g. "refs/entire/checkpoints//"), so callers at trust // boundaries — and future ones — can't silently push, fetch, or look up a bad // ref. func RefName(cid id.CheckpointID) (plumbing.ReferenceName, error) { if cid.Kind() == id.KindUnknown { return "", fmt.Errorf("cannot build checkpoint ref: invalid checkpoint ID %q", cid) } return plumbing.ReferenceName(CheckpointRefPrefix + cid.ShardFor() + "/" + cid.String()), nil }
// ParseRef extracts the checkpoint ID from a per-checkpoint ref name,
func TestRefName(t *testing.T) { t.Parallel()
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tt.want, RefName(tt.cid)) got, err := RefName(tt.cid) require.NoError(t, err) assert.Equal(t, tt.want, got) }) } }
func TestRefName_RejectsInvalidID(t *testing.T) { t.Parallel() for _, cid := range []id.CheckpointID{"", "not-an-id", "A1B2C3D4E5F6"} { _, err := RefName(cid) assert.Error(t, err, "RefName(%q) should error rather than build a malformed ref", cid) } }
func TestParseRef(t *testing.T) { t.Parallel()
if tt.wantOK { assert.Equal(t, tt.wantID, gotID) // Round-trip: building the ref from the parsed ID reproduces it. assert.Equal(t, tt.ref, RefName(gotID)) assert.Equal(t, tt.ref, mustRefName(t, gotID)) } else { assert.Equal(t, id.EmptyCheckpointID, gotID) } }