fix: anchored input patterns end at the last character (/D)
Without /D, "$" also matches before a trailing "\n", so "custom_meta_telefon\n", a color setting "5\n" (stored as sent) or a whole reference followed by "\n" passed VariableRef. Added /D to every ^...$ pattern that validates client or admin input: - VariableRef META_KEY, NUMBER, WHOLE (canonical/typeOf; Placeholders::field shares META_KEY) - Cursor::decode, GuideRepository topic names (MCP input and filter keys) - ExposurePolicy::sanitize ability keys and group ids, LogTab list filters Not changed: Placeholders::PATTERN (runs on trim()), Warnings hex checks (hints only), NodeSummary/AttrPathIndex/LogListTable (stored or Divi data, no client input). Each fixed pattern has a test with a trailing "\n" that is rejected. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -27,6 +27,12 @@ final class CursorTest extends TestCase
|
||||
self::assertNull(Cursor::decode(base64_encode('o:12;DROP')));
|
||||
}
|
||||
|
||||
/** "$" without /D also matches before a trailing newline – the cursor must end with the digits. */
|
||||
public function testCursorWithTrailingNewlineIsRejected(): void
|
||||
{
|
||||
self::assertNull(Cursor::decode(rtrim(strtr(base64_encode("o:5\n"), '+/', '-_'), '=')));
|
||||
}
|
||||
|
||||
public function testLimitIsClamped(): void
|
||||
{
|
||||
self::assertSame(20, Cursor::limit(null));
|
||||
|
||||
@@ -236,6 +236,20 @@ final class ExposurePolicyTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/** "$" without /D also matches before a trailing newline – ability names and group ids end with their last character. */
|
||||
public function testSanitizeRejectsKeysWithTrailingNewline(): void
|
||||
{
|
||||
self::assertSame(
|
||||
[],
|
||||
ExposurePolicy::sanitize([
|
||||
"lit/menu-list\n" => 'disabled',
|
||||
"@group:divi\n" => 'indirect',
|
||||
"@readonly:divi\n" => true,
|
||||
])
|
||||
);
|
||||
self::assertSame([], ExposurePolicy::sanitize(["@group:divi\n" => 'indirect'], ['core', 'divi']));
|
||||
}
|
||||
|
||||
public function testOldFlatOptionStaysValid(): void
|
||||
{
|
||||
$old = ['lit/content-get' => 'indirect', 'lit/menu-list' => 'direct'];
|
||||
|
||||
Reference in New Issue
Block a user