fix(relay): mint five-character log ids again

A 25-character upload capability is unreadable over the phone or in a
support thread, which is the only way these ids are ever exchanged.
Lookups stay bounded by the per-source failed-lookup limiter and the
three-day expiry, and ids minted at the longer shape are retired on the
next startup because they no longer match the store's filename shape.
This commit is contained in:
edde746
2026-07-28 03:30:32 +02:00
parent fd136f55f9
commit 314fec5383
2 changed files with 7 additions and 13 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ const (
pingInterval = 30 * time.Second pingInterval = 30 * time.Second
maxLogSize = 1 * 1024 * 1024 // 1MB maxLogSize = 1 * 1024 * 1024 // 1MB
logMaxAge = 3 * 24 * time.Hour logMaxAge = 3 * 24 * time.Hour
logIDLength = 25 logIDLength = 5
logRateInterval = 1 * time.Minute logRateInterval = 1 * time.Minute
logLookupRateBurst = 10 logLookupRateBurst = 10
logLookupRateSustained = 1 logLookupRateSustained = 1
+6 -12
View File
@@ -9,7 +9,6 @@ import (
"io" "io"
"io/fs" "io/fs"
"log" "log"
"math"
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@@ -2093,12 +2092,11 @@ func TestParseTrustedProxyCIDRs(t *testing.T) {
// generateLogID // generateLogID
// ====================================================================== // ======================================================================
// Random ids may legitimately repeat, so shape is the only contract here;
// collision retry is covered deterministically by
// TestLogStorePersistsAcrossRestartAndAvoidsIDCollisions.
func TestGenerateLogIDShape(t *testing.T) { func TestGenerateLogIDShape(t *testing.T) {
if entropyBits := float64(logIDLength) * math.Log2(float64(len(idChars))); entropyBits < 128 { for range 200 {
t.Fatalf("log capability entropy=%f bits, want at least 128", entropyBits)
}
seen := map[string]struct{}{}
for i := 0; i < 200; i++ {
id := generateLogID() id := generateLogID()
if len(id) != logIDLength { if len(id) != logIDLength {
t.Fatalf("len=%d want %d (id=%q)", len(id), logIDLength, id) t.Fatalf("len=%d want %d (id=%q)", len(id), logIDLength, id)
@@ -2108,10 +2106,6 @@ func TestGenerateLogIDShape(t *testing.T) {
t.Fatalf("id %q has unexpected char %q", id, c) t.Fatalf("id %q has unexpected char %q", id, c)
} }
} }
if _, dup := seen[id]; dup {
t.Fatalf("duplicate id %q after %d calls", id, i)
}
seen[id] = struct{}{}
} }
} }
@@ -6034,7 +6028,7 @@ func TestLogsUploadDoesNotWriteCapabilityToOperationalLog(t *testing.T) {
func TestLogStoreRetiresLegacyCapabilitiesOnStartup(t *testing.T) { func TestLogStoreRetiresLegacyCapabilitiesOnStartup(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()
now := time.Now().Add(-time.Minute) now := time.Now().Add(-time.Minute)
legacyID := "abcde" legacyID := strings.Repeat("a", 25) // capability shape used before ids went back to logIDLength
currentID := strings.Repeat("a", logIDLength) currentID := strings.Repeat("a", logIDLength)
legacyPath := filepath.Join(dir, legacyID+".log") legacyPath := filepath.Join(dir, legacyID+".log")
currentPath := filepath.Join(dir, currentID+".log") currentPath := filepath.Join(dir, currentID+".log")
@@ -6298,7 +6292,7 @@ func TestLogsGetUnknownIDIs404(t *testing.T) {
func TestLogsGetMalformedIDIs404(t *testing.T) { func TestLogsGetMalformedIDIs404(t *testing.T) {
h := newRelayHarness(t) h := newRelayHarness(t)
for _, id := range []string{"", "abc", "abcde", strings.Repeat("a", logIDLength+1), strings.Repeat("!", logIDLength)} { for _, id := range []string{"", "abc", strings.Repeat("a", logIDLength+1), strings.Repeat("a", 25), strings.Repeat("!", logIDLength)} {
resp, err := http.Get(h.baseURL + "/logs/" + id) resp, err := http.Get(h.baseURL + "/logs/" + id)
if err != nil { if err != nil {
t.Fatalf("get %q: %v", id, err) t.Fatalf("get %q: %v", id, err)