Overview

Discovered by @penyaskito at https://git.drupalcode.org/project/experience_builder/-/merge_requests/8...

Proposed resolution

  1. Test coverage
  2. Remove xb_visible_when_disabled, instead update \Drupal\experience_builder\Controller\ApiConfigControllers::list() like this:
    diff --git a/src/Controller/ApiConfigControllers.php b/src/Controller/ApiConfigControllers.php
    index e308597fe..783836733 100644
    --- a/src/Controller/ApiConfigControllers.php
    +++ b/src/Controller/ApiConfigControllers.php
    @@ -19,6 +19,8 @@ use Drupal\experience_builder\AssetRenderer;
     use Drupal\experience_builder\ClientSideRepresentation;
     use Drupal\experience_builder\ComponentSource\ComponentSourceInterface;
     use Drupal\experience_builder\Entity\XbHttpApiEligibleConfigEntityInterface;
    +use Drupal\experience_builder\EntityHandlers\ContentCreatorVisibleXbConfigEntityAccessControlHandler;
    +use Drupal\experience_builder\EntityHandlers\XbConfigEntityAccessControlHandler;
     use Drupal\experience_builder\Exception\ConstraintViolationException;
     use Drupal\experience_builder\Plugin\DataType\ComponentTreeStructure;
     use Drupal\experience_builder\Plugin\Field\FieldType\ComponentTreeItem;
    @@ -69,7 +71,12 @@ final class ApiConfigControllers extends ApiControllerBase {
         $storage = $this->entityTypeManager->getStorage($xb_config_entity_type_id);
         $query = $storage->getQuery()->accessCheck(TRUE);
         // Entity types can opt in to have disabled entities included in lists.
    -    if (!$xb_config_entity_type->get('xb_visible_when_disabled')) {
    +    $require_status_true = match ($xb_config_entity_type->getHandlerClass('access')) {
    +      ContentCreatorVisibleXbConfigEntityAccessControlHandler::class => FALSE,
    +      XbConfigEntityAccessControlHandler::class => TRUE,
    +      default => throw new \LogicException(),
    +    };
    +    if ($require_status_true) {
           $query->condition('status', TRUE);
         }
     
  3. Tighten access control:
    diff --git a/src/EntityHandlers/ContentCreatorVisibleXbConfigEntityAccessControlHandler.php b/src/EntityHandlers/ContentCreatorVisibleXbConfigEntityAccessControlHandler.php
    index a1bb474b6..ed89c4324 100644
    --- a/src/EntityHandlers/ContentCreatorVisibleXbConfigEntityAccessControlHandler.php
    +++ b/src/EntityHandlers/ContentCreatorVisibleXbConfigEntityAccessControlHandler.php
    @@ -6,6 +6,7 @@ namespace Drupal\experience_builder\EntityHandlers;
     
     use Drupal\Core\Access\AccessResult;
     use Drupal\Core\Access\AccessResultInterface;
    +use Drupal\Core\Config\Entity\ConfigEntityInterface;
     use Drupal\Core\Entity\EntityHandlerInterface;
     use Drupal\Core\Entity\EntityInterface;
     use Drupal\Core\Session\AccountInterface;
    @@ -15,10 +16,10 @@ final class ContentCreatorVisibleXbConfigEntityAccessControlHandler extends XbCo
       /**
        * {@inheritdoc}
        */
    -  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
    +  protected function checkAccess(ConfigEntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
         return match($operation) {
           // We always allow viewing these entities.
    -      'view' => AccessResult::allowed(),
    +      'view' => AccessResult::allowedIf($entity->status()),
           default => parent::checkAccess($entity, $operation, $account),
         };
       }
    diff --git a/src/EntityHandlers/XbConfigEntityAccessControlHandler.php b/src/EntityHandlers/XbConfigEntityAccessControlHandler.php
    index f588d457d..828aaee88 100644
    --- a/src/EntityHandlers/XbConfigEntityAccessControlHandler.php
    +++ b/src/EntityHandlers/XbConfigEntityAccessControlHandler.php
    @@ -7,6 +7,7 @@ namespace Drupal\experience_builder\EntityHandlers;
     use Drupal\Core\Access\AccessResult;
     use Drupal\Core\Access\AccessResultInterface;
     use Drupal\Core\Config\ConfigManagerInterface;
    +use Drupal\Core\Config\Entity\ConfigEntityInterface;
     use Drupal\Core\Entity\EntityAccessControlHandler;
     use Drupal\Core\Entity\EntityHandlerInterface;
     use Drupal\Core\Entity\EntityInterface;
    @@ -34,7 +35,7 @@ class XbConfigEntityAccessControlHandler extends EntityAccessControlHandler impl
       /**
        * {@inheritdoc}
        */
    -  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
    +  protected function checkAccess(ConfigEntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
         $adminPermission = $this->entityType->getAdminPermission();
         assert(is_string($adminPermission));
         return match($operation) {
    

    User interface changes

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

wim leers created an issue. See original summary.

wim leers’s picture

Issue summary: View changes
Status: Active » Needs work
Issue tags: +Needs tests
Parent issue: » #3452581: [META] XB Permissions

Tests still needed.

penyaskito’s picture

Assigned: penyaskito » wim leers
Status: Needs work » Needs review
Issue tags: -Needs tests

This has new tests, removes xb_visible_when_disabled, and behaves the same way as HEAD.
The only issue is that JavaScriptComponent is singled-out:

    $require_status_true = match ($xb_config_entity_type->getHandlerClass('access')) {
      ContentCreatorVisibleXbConfigEntityAccessControlHandler::class => FALSE,
      XbConfigEntityAccessControlHandler::class => ($xb_config_entity_type->id() !== JavaScriptComponent::ENTITY_TYPE_ID),
      default => throw new \LogicException(),
    };

This means that Pattern probably should have had the xb_visible_when_disabled flag too.
NR for confirmation.

wim leers’s picture

Assigned: wim leers » penyaskito
Status: Needs review » Needs work
Issue tags: +Needs tests
wim leers’s picture

Assigned: penyaskito » Unassigned
wim leers’s picture

mglaman’s picture

Assigned: Unassigned » mglaman

mglaman changed the visibility of the branch 0.x to hidden.

mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests
wim leers’s picture

Assigned: Unassigned » penyaskito
mglaman’s picture

Status: Needs review » Reviewed & tested by the community

RTBC, rerolled @penyaskito work. Called out a few items to discuss which look OK.

wim leers’s picture

This lost multiple performance optimizations for the crucial /xb/api/v0/config/component response — which is what is a critical factor in booting the XB UI! This is a big, and expensive response, and so the existing optimizations must be kept if at all possible.

Posted comments on the MR to explain this and pushed commits to bring those back while staying true to the spirit of the issue. There's at least one failure in need of debugging still.

Approved on the assumption that the remaining failure will be fixed while keeping both optimizations (the config entity query optimization as well as the cache tag response header optimization).

mglaman’s picture

Assigned: penyaskito » mglaman
Status: Reviewed & tested by the community » Needs work

CI failing but Wim made good fixes, I'll address

wim leers’s picture

Assigned: mglaman » wim leers

Dug deeper, because this can't land without passing e2e tests that this caused to fail.

The root cause for all the painful bits that were surfaced here is type: field.value.datetime. Introduced in 2014. Zero issues mention it! 🤯

  1. It dates back to #1989468-4: Weird messing with 'default_value_function' in date widgets ? (June 5, 2013 — aka 12 years and 1 day ago today), which I apparently reviewed (zero recollection)
  2. It has been causing confusion for years: #3137771: The configuration schema for datetime doesn't describe the field properties the way other field types do..
  3. It's actually still actively being refined: #3169876: Better handling of timezones for relative default date + times.

IOW: they’re not actually default values, but instructions for generating default values — wow! 🤯

I first wanted to open an upstream (core) issue titled Allow creating a default field value from a valid field value — but then I realized that literally defeats the point of #1989468-4: Weird messing with 'default_value_function' in date widgets ? — the very point is that no hardcoded value makes sense for datetime — only: "now" and "X time before/after now".

So, instead opening an XB follow-up. Because this is the first time the shape matching logic and infrastructure ends up … not working. 😬

wim leers’s picture

Assigned: wim leers » Unassigned

Attempted to fix it here, by special-casing the datetime and daterange field types in ::computeDefaultFieldValue(). 🤞

Need to shift to other things now…

wim leers’s picture

Status: Needs work » Needs review

Manual testing suggests that I succeeded in adding ::processDefaultValue() support? 🤞

wim leers’s picture

FYI: this is wildly out of scope here, but it happens to have been surfaced here 😬😭

Fortunately, all the access control changes are basically trivial, which is why this MR's size is still very manageable. So if #20 passes, then I'm gonna go ahead and merge, so we can all move on and pretend this was a bad nightmare 🧟‍♀️

wim leers’s picture

Title: ContentCreatorVisibleXbConfigEntityAccessControlHandler's `view` access must refuse access to disabled config entities » [PP-1] ContentCreatorVisibleXbConfigEntityAccessControlHandler's `view` access must refuse access to disabled config entities
Status: Needs review » Postponed
Related issues: +#3528362: Deterministic Component version hash should depend not only on source-specific settings, but also slots + explicit input schema

I hope all remaining failures are solved by #3528362: Deterministic Component version hash should depend not only on source-specific settings, but also slots + explicit input schema. Because they are AFAICT all like this:
[versioned_properties] The version 6c1061657e221db7 does not match the hash of the settings for this version, expected 0273dc5c85818057.

mglaman’s picture

This is postponed because we added lookup keys, right? Can we un-postpone this ticket is adding lookup keys for performance was spun out and blocked on that other ticket? That way we land the new access handlers albeit with a performance hit until lookup keys added?

Edit: we can still keep condition check but just not check lookup keys, so same as it was before

wim leers’s picture

Assigned: Unassigned » wim leers

Excellent call, @mglaman. Will make it so.

Note that lookup keys already exist (PageRegionuses them too). But it's the combination of

  • ApiConfigControllers::list() being modified here
  • restoring the Component config entity's lookup keys, to keep the intended optimization, even though it's absent in HEAD
  • a very old bug obscured through multiple layers of abstraction

… that caused it to go unnoticed.

Splitting out is worth it here to A) allow progress, B) improve archeology. Will do so 👍

wim leers’s picture

Title: [PP-1] ContentCreatorVisibleXbConfigEntityAccessControlHandler's `view` access must refuse access to disabled config entities » ContentCreatorVisibleXbConfigEntityAccessControlHandler's `view` access must refuse access to disabled config entities
Assigned: wim leers » Unassigned
Status: Postponed » Reviewed & tested by the community
wim leers’s picture

Issue tags: +Needs followup

I'll need to file a follow-up next week to bring back https://git.drupalcode.org/project/experience_builder/-/merge_requests/1...

  • wim leers committed 8c1737e1 on 0.x authored by mglaman
    Issue #3519878 by wim leers, penyaskito, mglaman, larowlan:...
wim leers’s picture

Status: Reviewed & tested by the community » Patch (to be ported)

Merged!

Happy weekend everyone.

penyaskito’s picture

Status: Patch (to be ported) » Fixed
Issue tags: -Needs followup

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.