settings-5 task 8: fix round 2 (NUL in an account is invalid in SQL too)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+11
−4
internal/registry/registry.go+6 −3internal/registry/updatesettings_test.go+5 −1
diff --git a/internal/registry/registry.go b/internal/registry/registry.go| index 3dafe927e..c838453b4 100644 |
| --- a/internal/registry/registry.go |
| +++ b/internal/registry/registry.go |
| @@ -1119,10 +1119,13 @@ func EffectiveAccount(account string) string { |
| // effectiveAccountSQL is EffectiveAccount as a SQLite expression over col. |
| // controlname.ValidAccount is ^[a-z]{3,16}$: three to sixteen characters, |
| -// none outside a-z. TestEffectiveAccountSQLIsEffectiveAccount pins the two |
| -// together. |
| +// none outside a-z. SQLite's length and GLOB both stop at an embedded NUL, |
| +// so the NUL is rejected explicitly (instr compares the whole value); |
| +// without that "abc\x00x" would read as the valid "abc" while Go rejects it. |
| +// TestEffectiveAccountSQLIsEffectiveAccount pins the two together. |
| func effectiveAccountSQL(col string) string { |
| - return `(CASE WHEN length(` + col + `) BETWEEN 3 AND 16 AND ` + col + ` NOT GLOB '*[^a-z]*' THEN ` + col + |
| + return `(CASE WHEN length(` + col + `) BETWEEN 3 AND 16 AND instr(` + col + `, char(0)) = 0 AND ` + col + |
| + ` NOT GLOB '*[^a-z]*' THEN ` + col + |
| ` ELSE '` + opsAccount + `' END)` |
| } |
diff --git a/internal/registry/updatesettings_test.go b/internal/registry/updatesettings_test.go| index 17fd5ad82..0dcc695d7 100644 |
| --- a/internal/registry/updatesettings_test.go |
| +++ b/internal/registry/updatesettings_test.go |
| @@ -119,6 +119,9 @@ func TestAnEquivalentAccountSpellingIsTheSameTenant(t *testing.T) { |
| state := `{"known":true,"replica":true}` |
| for _, tc := range []struct{ from, to string }{ |
| {"", "bab"}, {"bab", ""}, {"", ""}, {"NOT-VALID", "bab"}, {"bab", "x"}, |
| + // Astra r5 N1: an embedded NUL is invalid (SQLite's length and |
| + // GLOB stop at it), so these are the ops account too. |
| + {"abc\x00x", "bab"}, {"bab", "abc\x00x"}, {"abc\x00x", ""}, {"abc\x00", "bab"}, {"\x00", "bab"}, {"abc\x00x", "abc\x00y"}, |
| } { |
| if err := reg.Upsert(Route{Host: host, Kind: "instance", Account: tc.from, App: "km", UpdateSettings: settings, BuildState: state}); err != nil { |
| t.Fatal(err) |
| @@ -153,7 +156,8 @@ func TestEffectiveAccountSQLIsEffectiveAccount(t *testing.T) { |
| t.Fatal(err) |
| } |
| for _, a := range []string{"", "bab", "bes", "abc", "ab", "a", "abcdefghijklmnop", "abcdefghijklmnopq", |
| - "Abc", "ABC", "ab1", "a-b", "a_b", "a b", " abc", "abc ", "abc\n", "\u00e1bc", "ab\u00e1", "ab]", "ab^", "ab*", "ab?", "ab["} { |
| + "Abc", "ABC", "ab1", "a-b", "a_b", "a b", " abc", "abc ", "abc\n", "\u00e1bc", "ab\u00e1", "ab]", "ab^", "ab*", "ab?", "ab[", |
| + "abc\x00x", "abc\x00", "\x00abc", "\x00", "abc\x00\x00", "ab\x00", "abcdefghijklmnop\x00x"} { |
| var got string |
| if err := reg.sql.QueryRow(`SELECT `+effectiveAccountSQL("?1"), a).Scan(&got); err != nil { |
| t.Fatal(err) |