-
Notifications
You must be signed in to change notification settings - Fork 122
fix(log): honor whitespace and array-shaped IP values in exclude rule #1932
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -242,9 +242,18 @@ public function record_matches_rules( $record, $exclude_rules ) { | |
| } | ||
|
|
||
| if ( 'ip_address' === $exclude_key ) { | ||
| $ip_addresses = explode( ',', $exclude_value ); | ||
|
|
||
| if ( in_array( $record['ip_address'], $ip_addresses, true ) ) { | ||
| // Stored value shape varies: the admin form posts one | ||
| // comma-joined string per row, while a direct API or test | ||
| // caller can hand us an array of IPs. Normalize first, then | ||
| // trim and drop empties so a stored "1.1.1.1, 8.8.8.8" or | ||
| // ["1.1.1.1", " 8.8.8.8"] both match a real client IP. | ||
| $ip_addresses = is_array( $exclude_value ) | ||
| ? $exclude_value | ||
| : explode( ',', (string) $exclude_value ); | ||
|
Comment on lines
+250
to
+252
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Warning: I could not find operational code that gives an array to this parameter. Thus this branch is not necessary. I examined each path that supplies
Only the test in this PR gives an array to this function. Thus the test is the only proof that the branch is necessary, but the test is also a part of this PR. Do one of these two things. Show operational code that gives an array. Or remove this branch and the two array assertions in the test (lines 240-262). The |
||
|
|
||
| $ip_addresses = array_filter( array_map( 'trim', $ip_addresses ) ); | ||
|
|
||
| if ( ! empty( $record['ip_address'] ) && in_array( $record['ip_address'], $ip_addresses, true ) ) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Warning: the When the code gets to this line, two things are already true. The condition But an empty record IP address does occur in operation. When Thus, if you added this condition for that reason, the condition is in the wrong place. It hides the problem here, but the correction belongs at the source in If the condition is only defensive, tell that in a comment. At this time, |
||
| ++$matches_found; | ||
| } | ||
| } elseif ( $record[ $exclude_key ] === $exclude_value ) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -181,4 +181,136 @@ public function test_can_match_record_id_address() { | |
| ) | ||
| ); | ||
| } | ||
|
|
||
| public function test_ip_address_rule_matches_with_whitespace() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: this test method makes assertions about four different behaviors, but the name tells about only one behavior. The four behaviors are: removal of spaces, an empty record IP, removal of empty items, and an array value. If the test fails, the name of the test will point to the incorrect behavior. Divide this test into more than one test. Or give it a more general name, for example |
||
| // Whitespace around commas (admin form join + user paste) must not | ||
| // silently fail the IP match. See issue #1824. | ||
| $this->assertTrue( | ||
| $this->plugin->log->record_matches_rules( | ||
| array( | ||
| 'ip_address' => '8.8.8.8', | ||
| ), | ||
| array( | ||
| 'ip_address' => '1.1.1.1, 8.8.8.8', | ||
| ), | ||
| 'Trailing space after comma does not break the match' | ||
| ) | ||
| ); | ||
|
|
||
| $this->assertTrue( | ||
| $this->plugin->log->record_matches_rules( | ||
| array( | ||
| 'ip_address' => '8.8.8.8', | ||
| ), | ||
| array( | ||
| 'ip_address' => '8.8.8.8 ', | ||
| ), | ||
| 'Trailing space on a single-IP rule still matches' | ||
| ) | ||
| ); | ||
|
|
||
| $this->assertFalse( | ||
| $this->plugin->log->record_matches_rules( | ||
| array( | ||
| 'ip_address' => '', | ||
| ), | ||
| array( | ||
| 'ip_address' => '1.1.1.1', | ||
| ), | ||
| 'Empty record IP never matches an IP-only rule' | ||
| ) | ||
| ); | ||
|
|
||
| // Empty tokens between commas (e.g. user-pasted "1.1.1.1, ,") must be | ||
| // dropped, not treated as a valid match against the empty record IP. | ||
| $this->assertTrue( | ||
| $this->plugin->log->record_matches_rules( | ||
| array( | ||
| 'ip_address' => '1.1.1.1', | ||
| ), | ||
| array( | ||
| 'ip_address' => '1.1.1.1, ,', | ||
| ), | ||
| 'Empty comma-separated tokens are dropped before matching' | ||
| ) | ||
| ); | ||
|
|
||
| // Stored value may already be an array (direct API callers, tests). | ||
| // Both shapes must match. | ||
| $this->assertTrue( | ||
| $this->plugin->log->record_matches_rules( | ||
| array( | ||
| 'ip_address' => '8.8.8.8', | ||
| ), | ||
| array( | ||
| 'ip_address' => array( '127.0.0.1', '8.8.8.8' ), | ||
| ), | ||
| 'Array-shaped IP rule matches the second entry' | ||
| ) | ||
| ); | ||
|
|
||
| $this->assertTrue( | ||
| $this->plugin->log->record_matches_rules( | ||
| array( | ||
| 'ip_address' => '8.8.8.8', | ||
| ), | ||
| array( | ||
| 'ip_address' => array( ' 8.8.8.8 ' ), | ||
| ), | ||
| 'Array-shaped IP rule trims whitespace per entry' | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| public function test_ip_only_exclude_rule_excludes_record() { | ||
| // End-to-end coverage for the bug in #1824. Shape mirrors the | ||
| // parallel-array rule format produced by both the wp-admin Exclude | ||
| // list and the stream/create-exclusion-rule ability. | ||
| $this->plugin->settings->options['exclude_rules'] = array( | ||
| 'exclude_row' => array( 0 => '' ), | ||
| 'author_or_role' => array( 0 => '' ), | ||
| 'connector' => array( 0 => '' ), | ||
| 'context' => array( 0 => '' ), | ||
| 'action' => array( 0 => '' ), | ||
| 'ip_address' => array( 0 => '127.0.0.1' ), | ||
| ); | ||
|
|
||
| $user = $this->factory->user->create_and_get(); | ||
| $user->add_role( 'administrator' ); | ||
|
|
||
| $this->assertTrue( | ||
| $this->plugin->log->is_record_excluded( | ||
| 'users', | ||
| 'profile', | ||
| 'updated', | ||
| $user, | ||
| '127.0.0.1' | ||
| ), | ||
| 'IP-only rule excludes a record from the matching IP' | ||
| ); | ||
|
|
||
| $this->assertFalse( | ||
| $this->plugin->log->is_record_excluded( | ||
| 'users', | ||
| 'profile', | ||
| 'updated', | ||
| $user, | ||
| '8.8.8.8' | ||
| ), | ||
| 'IP-only rule does not exclude a record from a different IP' | ||
| ); | ||
|
|
||
| // Whitespace in the stored IP value must still match. | ||
| $this->plugin->settings->options['exclude_rules']['ip_address'][0] = '127.0.0.1, 8.8.8.8'; | ||
| $this->assertTrue( | ||
| $this->plugin->log->is_record_excluded( | ||
| 'users', | ||
| 'profile', | ||
| 'updated', | ||
| $user, | ||
| '8.8.8.8' | ||
| ), | ||
| 'Comma-joined IP list with whitespace matches the second entry' | ||
| ); | ||
| } | ||
|
Comment on lines
+265
to
+315
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blocker: this test does not show the defect in #1824, and I do not think that whitespace is the cause of that report. Evidence 1: the screenshot in the issue The screenshot shows one rule row. Author or Role, Context, and Action all show the placeholder text. The IP Address cell has exactly one select2 tag: One tag. No comma. Thus the stored value is a bare Evidence 2: the test passes without the correction I changed Evidence 3: I reproduced a different cause on macOS The reporter uses macOS. On macOS, the name Thus, when the web server accepts IPv6 and the user opens The value depends on the address that the server accepts, not on the text that the user writes. Thus a user can open A probe test with a rule of This agrees with the report: the rule does nothing, and no error message occurs. Note that this is not a defect in the comparison. How to reproduce this without the reporter
Step 6 is the proof. If the rule operates with A second, different defect that I found This one is real, but it is probably not the defect of this reporter. A chain gives What to do
The whitespace correction is good. My objection is only to the statement that it closes #1824. |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: the comment has five lines, but the code has four lines.
The comment also tells about a "direct API or test caller". I could not find such a caller. See my other comment about the array branch.
Two lines are sufficient: the admin form joins the values with commas, thus the code must remove the spaces before the strict comparison.