package service
import (
"errors"
"strings"
"testing"
)
// The read plane must never be talkable into serving proposal content. gitx
// resolves ref names happily, so this guard is the only thing standing between
// a crafted rev and unreviewed text entering an agent's context as approved.
func TestValidateReadRevRefusesRefNames(t *testing.T) {
sha := strings.Repeat("a1b2c3d4", 5) // 40 hex chars
for _, tc := range []struct {
name string
rev string
ok bool
}{
{"approved head sentinel", ApprovedRev, true},
{"full object name", sha, true},
{"proposal branch", "proposals/42", false},
{"approved branch by name", "main", false},
{"HEAD", "HEAD", false},
{"tag", "refs/tags/v1", false},
{"abbreviated sha", sha[:12], false},
{"uppercase hex", strings.ToUpper(sha), false},
{"sha with trailing path", sha + "/x", false},
{"almost hex", strings.Repeat("g", 40), false},
} {
t.Run(tc.name, func(t *testing.T) {
err := ValidateReadRev(tc.rev)
if tc.ok && err != nil {
t.Fatalf("ValidateReadRev(%q) = %v, want nil", tc.rev, err)
}
if !tc.ok {
if err == nil {
t.Fatalf("ValidateReadRev(%q) = nil, want rejection", tc.rev)
}
if !errors.Is(err, ErrBadReadRev) {
t.Fatalf("ValidateReadRev(%q) error = %v, want ErrBadReadRev", tc.rev, err)
}
}
})
}
}