Skip to content
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

WordPress - Display site-theme/decorations on error screens #22805

Conversation

braders
Copy link
Contributor

@braders braders commented Feb 20, 2022

Overview

This builds on the previous work completed by @seamuslee001 in #20206, but addresses some concerns with the original approach.

This new approach keeps the use of CRM_Core_Exception, ensuring that existing logging and hooks are not lost. As WordPress does not have a generic theme() function to theme a generic error message we need to ensure that the execution does not exit to allow the error message to be dropped into the page content - demonstated with a couple of default themes:

Screenshot 2022-02-20 at 16 27 47

Screenshot 2022-02-20 at 16 28 22

Before

Previously a completely unbranded, and minimally styled error page was used:
Screenshot 2022-02-20 at 16 29 36

After

The error message is embedded in the post content, as demonstrated in the screnshots above.

Technical Details

There may be some (legitimate) concerns about not calling exit after an error, which is fair - consideration should be given to whether I'm missing anything when reviewing this.

I did wonder if the $civicrm_wp_title variable should be set within the CRM_Core_Error method to avoid leaking information when exceptions happen which don't pass through the permissionDenied method. Ultimately I decided this probably wasn't a big risk, but it would be good to check no one else disagrees here.

This can be tested in two ways:

  • Manually trigger an exception on the page you are viewing by adding throw new CRM_Core_Exception('This is a test exception') to the relevant form. (unless you know of a specific route which causes a legitimate exception).
  • Visit a page you don't have permissions to view in order to trigger the permissionDenied method.

@civibot
Copy link

civibot bot commented Feb 20, 2022

(Standard links)

@civibot civibot bot added the master label Feb 20, 2022
@braders braders force-pushed the permission_denied_wordpress_improvement-alternative branch from 5b99ebf to b7760d3 Compare February 20, 2022 16:44
@christianwach
Copy link
Member

This looks much better than previous solutions 👍

@braders Quick question (I haven't time today to r-run) I assume the backtrace isn't shown when:

define('WP_DEBUG_DISPLAY', false);

@braders
Copy link
Contributor Author

braders commented Feb 22, 2022

This looks much better than previous solutions 👍

@braders Quick question (I haven't time today to r-run) I assume the backtrace isn't shown when:

define('WP_DEBUG_DISPLAY', false);

I'd need to review what Civi does in some more detail to be certain, but I think the display (or not) of the backtrace would be completely down to whether Civi is configured to display debug information - I'm fairly sure there is a system settings page where is is set. I don't think CiviCRM reads WP_DEBUG_DISPLAY by default, and I've not added any logic to read this constant.

@totten
Copy link
Member

totten commented Mar 9, 2022

That does look like a nicer error screen!

Here are some random thoughts. These are not all blockers - just general feedback/observations/suggestions.

  • Naming:
    • CRM_Utils_System::exitAfterFatal(); returns a boolean to describe a policy -- it should have a name that sounds like a boolean or policy. (Ex: isExitRequired() or doesFatalRequireExit()).
    • CRM_Core_Error::abend(...bool $exit) - The function is called "end" (as in "abnormal end of execution"; as in "the system is crashing"). bool $exit reads as a little redundant. (As in: "Do you really want the function to do what it says?")
  • Mark functions as @internal: Support for CRM_Utils_System::* ranges widely - some functions are "absolutely critical, public-facing APIs that could only break with major Civi v6.0 bump"; others are "totally quirky, internal-only, could change next month". The @internal annotation would remove ambiguity and make it easier/safer for future iterations.
  • Target Environment: I feel a little ambivalent about targeting by CMS/UF (WordPress).
    • The code-paths around page-rendering and around errors can be sometimes weird and sometimes CMS-dependent. r-runing is complicated, and focusing on one CMS keeps the scope-of-work narrower.
    • If you talked to a dozen site-builders about error-handling behaviors, I bet the desired behaviors would not fall neatly along CMS lines
  • Root Problem: The root problem is that the contract around invoke()/runItem()/throw $exception/PEAR_Error/fatal() feels a bit like a porcupine. The ideal is to grok+improve that contract. (Though it may be a heavy lift.)
  • Test Coverage: E2E test-coverage would be great. Maybe something like:
    class E2E_Core_ErrorReportingTest extends CiviEndToEndTestCase {
      use Civi\Test\HttpTestTrait;
      public function testErrorChrome() {
        if (CIVICRM_UF !== 'WordPress') $this->markTestIncomplete('Not yet adapted to Drupal/Joomla/etc');
    
        $http = $this->createGuzzle([
          'authx_user' => $GLOBALS['_CV']['ADMIN_USER'], // Send HTTP requests as admin
          'http_errors' => FALSE, // We're expecting errors. It's easier to inspect if Guzzle doesn't its own exceptions.
        ]);
        $response = $http->get('frontend://civicrm/some/page?with=baddata&to=provokeError');
        // Assert that $response has HTTP code 404 or 500 or somesuch.
        // Assert that $response has some error message
        // Assert that $response has some kind of site-specific chrome
      }
    
      // NOTE: May need to borrow E2E_Extern_AuthxRestTest::setUpBeforeClass
    }

@braders
Copy link
Contributor Author

braders commented Mar 27, 2022

@totten Thanks for the feedback. My latest push addresses:

  • Naming
  • Mark functions as @internal
  • I also realised that following this change, the HTTP 500 code was not being used. That has also been addressed.

@braders braders force-pushed the permission_denied_wordpress_improvement-alternative branch from a5d6d70 to 8be79db Compare March 27, 2022 10:52
@demeritcowboy
Copy link
Contributor

jenkins retest this please. Known intermittent timestamp-rollover fail, which is touchy to fix because was part of a security release.

CRM_Core_BAO_CustomFieldTest::testFileDisplayValueNoDescription
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'              <a href="/index.php?q=civicrm/file&amp;reset=1&amp;id=1&amp;eid=3&amp;fcs=51f30f984798b52fad8a796708bd26e8fe38ced0434f743c67369d07ec3db20d_1648379262_168" title="test_file.txt">\n
+'              <a href="/index.php?q=civicrm/file&amp;reset=1&amp;id=1&amp;eid=3&amp;fcs=51f30f984798b52fad8a796708bd26e8fe38ced0434f743c67369d07ec3db20d_1648379263_168" title="test_file.txt">\n

@eileenmcnaughton
Copy link
Contributor

@seamuslee001 @christianwach @totten - is this mergeable now?

@kcristiano
Copy link
Member

@christianwach The debug display is controlled by CiviCRM's debug handling. I've done some r-run on this and it looks good to me. I am OK to merge.

@eileenmcnaughton eileenmcnaughton added the merge ready PR will be merged after a few days if there are no objections label Apr 17, 2022
@eileenmcnaughton
Copy link
Contributor

I've added merge-ready based on @kcristiano ^^ - if we don't get further feedback we can merge

@totten
Copy link
Member

totten commented Apr 19, 2022

Yeah, I think the updates from @braders look like a good improvement. 👍

I've written an end-to-end test to check the quality of error screens across different environments (#23257).

(@braders) I also realised that following this change, the HTTP 500 code was not being used. That has also been addressed.

Something seems off:

  • ⚠️ In my testing of a CRM_Core_Error::fatal() and throw new \Exception() on WordPress (with or without the current PR), it incorrectly returns HTTP 200. (You would expect HTTP 500.)
  • ✔️ The PR title references the "permission denied" scenario - for that scenario, you'd expect HTTP 403. In my testing, it does give HTTP 403. (So sometimes it does it does set an HTTP status-code.)

But I think the status-code is maybe tangential:

  • The focus of the PR description seems to be more about showing the site's chrome/decorations around the error. I confirmed that my WP site displays the chrome/decorations. Tested via r-run and testErrorChrome.
  • The status-code seems to be a secondary thought in the PR. In my testing (testErrorStatus), it is neither better nor worse.

I think it would be great to also resolve discrepancies in the error-status (and remove this opt-out), but that doesn't need to block improvements on the chrome/decoration.

@totten totten changed the title Improve Permission denied handling in WordPress WordPress - Display site-theme/decorations on error screens Apr 20, 2022
@totten totten merged commit 201cf15 into civicrm:master Apr 20, 2022
totten added a commit to totten/civicrm-core that referenced this pull request May 6, 2022
This test was added during 5.50.alpha (civicrm#23257, civicrm#22805).  It's purpose is to
assert that the page-chrome/site-wide-template is present.  It appears that
the markup from WordPress has changed slightly.  (It may be that I
originally tested against an older version of WP.) In any event, this
relaxes the test so that it also passes on a newer WP build.
totten added a commit to totten/civicrm-core that referenced this pull request May 6, 2022
This test was added during 5.50.alpha (civicrm#23257, civicrm#22805).  It's purpose is to
assert that the page-chrome/site-wide-template is present on certain
error-messages; however, the underlying behavior was only implemented on
WordPress. It has not yet been implemented on other CMS.

Before
------

* __WordPress__: Runs testErrorChrome. Expected to pass.
* __Drupal 7__: Skip testErrorChrome (mostly) because it is expected to fail.
* __Drupal 8+, Backdrop__: Runs testErrorChrome. Fails.

After
-----

* __WordPress__: Runs testErrorChrome. Expected to pass.
* ___Drupal 7, Drupal 8+, Backdrop__: Skip testErrorChrome (mostly) because it is expected to fail.
totten added a commit to totten/civicrm-core that referenced this pull request May 6, 2022
This test was added during 5.50.alpha (civicrm#23257, civicrm#22805).  It's purpose is to
assert that the page-chrome/site-wide-template is present on certain
error-messages; however, the underlying behavior was only implemented on
WordPress. It has not yet been implemented on other CMS.

Before
------

* __WordPress__: Runs testErrorChrome. Expected to pass.
* __Drupal 7__: Skip testErrorChrome (mostly) because it is expected to fail.
* __Drupal 8+, Backdrop__: Runs testErrorChrome. Fails.

After
-----

* __WordPress__: Runs testErrorChrome. Expected to pass.
* ___Drupal 7, Drupal 8+, Backdrop__: Skip testErrorChrome (mostly) because it is expected to fail.

Comment
-------

It still runs `testErrorChrome` for `permission` errors; per MM discussion, it appears that this does actually work, but we need
to tune assertion for BD+D8.
totten added a commit to totten/civicrm-core that referenced this pull request May 6, 2022
This test was added during 5.50.alpha (civicrm#23257, civicrm#22805).  It's purpose is to
assert that the page-chrome/site-wide-template is present on certain
error-messages; however, the underlying behavior was only implemented on
WordPress. It has not yet been implemented on other CMS.

Before
------

* __WordPress__: Runs testErrorChrome. Expected to pass.
* __Drupal 7__: Skip testErrorChrome (mostly) because it is expected to fail.
* __Drupal 8+, Backdrop__: Runs testErrorChrome. Fails.

After
-----

* __WordPress__: Runs testErrorChrome. Expected to pass.
* ___Drupal 7, Drupal 8+, Backdrop__: Skip testErrorChrome (mostly) because it is expected to fail.

Comment
-------

It still runs `testErrorChrome` for `permission` errors; per MM discussion, it appears that this does actually work, but we need
to tune assertion for BD+D8.
darrick pushed a commit to darrick/civicrm-core that referenced this pull request May 7, 2022
….1+)

Import - also export invalid as export error

I found that rows that fail validation are marked 'invalid'
rather than error & won't show on the preview screen.

I guess I could check for invalid vs error separately
- gets kinda weird though - if you leave them
in the file you are importing surely they are still errors
to see on the summary screen even though
you knew they were invalid on the Preview?

(E2E) testErrorChrome - Skip Backdrop and D8+ (much like D7)

This test was added during 5.50.alpha (civicrm#23257, civicrm#22805).  It's purpose is to
assert that the page-chrome/site-wide-template is present on certain
error-messages; however, the underlying behavior was only implemented on
WordPress. It has not yet been implemented on other CMS.

Before
------

* __WordPress__: Runs testErrorChrome. Expected to pass.
* __Drupal 7__: Skip testErrorChrome (mostly) because it is expected to fail.
* __Drupal 8+, Backdrop__: Runs testErrorChrome. Fails.

After
-----

* __WordPress__: Runs testErrorChrome. Expected to pass.
* ___Drupal 7, Drupal 8+, Backdrop__: Skip testErrorChrome (mostly) because it is expected to fail.

Comment
-------

It still runs `testErrorChrome` for `permission` errors; per MM discussion, it appears that this does actually work, but we need
to tune assertion for BD+D8.

(E2E) `testErrorChrome` - Update to work with current wp-demo build

This test was added during 5.50.alpha (civicrm#23257, civicrm#22805).  It's purpose is to
assert that the page-chrome/site-wide-template is present.  It appears that
the markup from WordPress has changed slightly.  (It may be that I
originally tested against an older version of WP.) In any event, this
relaxes the test so that it also passes on a newer WP build.

(E2E) testErrorChrome - Revise page-chrome check for all Drupal-style UFs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
master merge ready PR will be merged after a few days if there are no objections
Projects
None yet
6 participants