Problem/Motivation

In #2942975-33: [PP-1] Expose Layout Builder data to REST and JSON:API @Wim Leers pointed out that there was no field level access to Layout Builder's override field.

He also pointed out the implications of exposing this field over the API for read and write access.

For read:

Once we make this available via APIs, we have to support it forever. Are we confident enough to commit to that?

For write:

To be more precise: there is no active need for validation logic, because the UI is structured in such a way that only trusted logic ever generates values to be stored.

My biggest fear is letting API clients writing layout information. AFAICT validation is absent. Which is fine for the coupled UI because it naturally limits what data can be saved, but not for a decoupled UI. I've explained why this can easily lead to broken sites at minimum, and information disclosure at worst.

For more details read the linked comment.

To avoid this problem we can first not expose this field via the API at all.

If we expose the field over the API it would be effectively just that same as saying we support modules getting the json string decoding it and figuring out the layout from there. Because this is effectively what a decoupled application would be doing.

And once we expose we can never change that structure. Though in theory we could write a BC layer to with a normalizer to keep the format the same for sites that want it the same. But considering how much discussion there was around #2751325: All serialized values are strings, should be integers/booleans when appropriate and #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX I think that is something we want to avoid at all costs if we can.

Therefore we could be free to change the raw array structure the field was stored in until we make the field available over the API.

original problem
While reviewing #2942975: [PP-1] Expose Layout Builder data to REST and JSON:API, I noticed that anybody who is allowed to update a given entity is also allowed to modify its layout. Given the existence of the configure any layout permission, I don't think this is intentional?

Proposed resolution

Implement \Drupal\layout_builder\Field\LayoutSectionItemList::defaultAccess() and always return access forbidden.
We could instead implement \Drupal\layout_builder\Field\LayoutSectionItemList::access() but this would mean that no code could alter that access. Maybe that is what we want.

If we chose defaultAccess() we could still give the option to those really living on the edge to alter the access and provide their own normalizers. Of course they would get no BC support. I think the fact that they would need to both alter the access and provide their own normalizers would make it very clear we don't offer BC. We can't be expected to offer BC for custom normalizers.

If implemented access()it would still be possible for modules to alter the access by implementing hook_field_info_alter and switching their own field class similar to language_field_info_alter(). Perhaps this would be a stronger signal that we don't intend to offer API BC support for the internal field structure.

If we forbid all API access to the field now we could in stages:

  1. Provide read access.
    At this point we would have to be fairly confident that the field structure is not going to change or that we would provide a BC normalization layer to keep it in the same format for existing sites.
  2. Provide write access
    At this point we would also have to have validation for the field type.

It would also be possible for these 2 stages to happen in contrib by using the above mentioned methods of altering the field access and providing a normalizer. This may give more assurance the we get the API we offer to decoupled apps(as opposed to code level API) right the first time. We could have real world use cases before we are stuck with a particular format forever.

Remaining tasks

Discuss.

User interface changes

None

API changes

Instead of getting an empty array for the layout field via REST the field would not be return at all for Rest responses.

Data model changes

None

Release notes snippet

How to test

This comes from comment #12:

You could test by:

Turn on REST and Layout Builder
Enable Layout overrides for articles
Enable ReST Get requests on Articles. Probably easiest with https://www.drupal.org/project/restui
Make a get request for an article node with an override https://www.drupal.org/docs/8/core/modules/rest/2-get-for-reading-conten...
Inspect the JSON response
Without the patch: There should be a key for layout_builder__layout
You probably need to save the node in between requests. No need to change the layout. Just change the title to make sure you aren't getting a cached response.
With the patch: There should NOT be a key for layout_builder__layout

Comments

Wim Leers created an issue. See original summary.

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new1.24 KB

Status: Needs review » Needs work

The last submitted patch, 2: 3028301-2.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new907 bytes
new1.34 KB

Well that was silly. (Canceled testing #2.)

tedbow’s picture

StatusFileSize
new3.17 KB
new4.4 KB

@Wim Leers thanks for finding this.

Perhaps the intent is "if you can edit the entity, you can also change its layout"?

No that is not the intent.

Here are is unit test for access.

Status: Needs review » Needs work

The last submitted patch, 5: 3028301-5.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new548 bytes
new4.43 KB

Wow I forgot @group for the new test file. Totally never did that before 😉

tedbow’s picture

Title: Add default field-level access restriction to Layout Builder's field type » Forbid field level access to access to Layout Builder's field type to prevent exposing the field over the API
Issue summary: View changes
StatusFileSize
new4.03 KB
new1019 bytes

Updated/repurposed the issue.

This patch implements \Drupal\layout_builder\Field\LayoutSectionItemList::defaultAccess()

See the summary for reasons

I removed the unit test because there is no logic in the method now.

tedbow’s picture

Issue summary: View changes
tim.plunkett’s picture

Moving the tag here

kristen pol’s picture

The patch in #8 is clear but I'm not sure how to test this manually. Thoughts?

tedbow’s picture

@Kristen Pol thanks for the offer to test. Basically this patch should make it so the field 'layout_builder__layout' is return on REST GET request.

You could test by:

  1. Turn on REST and Layout Builder
  2. Enable Layout overrides for articles
  3. Enable ReST Get requests on Articles. Probably easiest with https://www.drupal.org/project/restui
  4. Make a get request for an article node with an override https://www.drupal.org/docs/8/core/modules/rest/2-get-for-reading-conten...
  5. Inspect the JSON response
  6. Without the patch: There should be a key for layout_builder__layout
  7. You probably need to save the node in between requests. No need to change the layout. Just change the title to make sure you aren't getting a cached response.
  8. With the patch: There should NOT be a key for layout_builder__layout
tedbow’s picture

Issue tags: +Needs tests
StatusFileSize
new1.97 KB
new2.96 KB

I realized now after #2724823: EntityResource: read-only (GET) support for configuration entities you can actually make GET rest request for config entities. So we need to make sure that the sections are not return with that entity either. Since it is not a fieldable entity we will actually have to have our own normalizer.

This patch just adds the normalizer. We will need test for the normalizer and probably rest test to show it does not get returned.

tedbow’s picture

Title: Forbid field level access to access to Layout Builder's field type to prevent exposing the field over the API » Do not expose to Layout Builder's sections either in defaults or overrides to REST and other external APIs

Changing title to encompass more that just the field

xjm’s picture

Issue tags: +Needs change record

The overall plan described in the issue summary sounds correct to me from a release management perspective. I checked with @tedbow and right now HEAD just gives you:
[]
So there's no real BC break for the beta by adding this restriction now.

+1 for forbidding access by default, but still making a workaround possible if needed. What's missing from the patch right now is:

  1. Something warning the site owner that BC is not provided if they choose to alter the access and create a custom normalizer.
  2. A @todo referencing a followup that will add read access to the intentionally designed API. (The warning above could also reference this issue, so that the deliberately living-on-the-edge developer knows when they will need to change their custom code.)
  3. A change record.

Other than that, I'm comfortable signing off on the general approach here from a release management perspective, and we also have @Wim Leers' (implied) signoff as API-first maintainer.

Thanks!

xjm’s picture

To clarify #15 after discussing with Ted in Slack, we need to document in the patch why we're restricting access and why we're not exposing sections in the normalizer, with @todos. Let's see what that looks like firstt. And then if those docs do mention overriding the access as a workaround, then they might need the warning of that not having BC.

tedbow’s picture

StatusFileSize
new9.06 KB
new12.03 KB

@xjm thanks for the comment

This patch adds REST coverage for the override field

Tests override field with rest:

  1. Doesn't get returned in GET
  2. Including in PATCH get 403
  3. Including in POST gets 403

We still need GET test for defaults. Other methods are not supported on config entities.

The last submitted patch, 17: interdiff-13-16.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tedbow’s picture

StatusFileSize
new4.73 KB
new13.35 KB

This patch adds the rest test coverage for layout defaults.

The last submitted patch, 17: 3028301-16.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 19: 3028301-19.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new4.56 KB
new15.52 KB

No sure why this is failing. It is passing for me locally.

I am going to try to switch to json_decode directly to decode. Just running this 1 test.

Status: Needs review » Needs work

The last submitted patch, 22: 3028301-22.patch, failed testing. View results

wim leers’s picture

  1. index 2085b9737b..870f411540 100644
    --- a/core/drupalci.yml
    
    @@ -47,3 +47,10 @@ services:
    +  layout_builder.normalizer.layout_entity_display:
    +    class: Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer
    
    @@ -0,0 +1,28 @@
    +class LayoutEntityDisplayNormalizer extends ConfigEntityNormalizer {
    

    AFAICT this is out of scope for this issue, but it's just here for testing?

  2. +++ b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
    @@ -74,4 +76,11 @@ public function equals(FieldItemListInterface $list_to_compare) {
    +  public function defaultAccess($operation = 'view', AccountInterface $account = NULL) {
    +    return AccessResult::forbidden();
    +  }
    

    👍

  3. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/SectionsNotExposed.php
    @@ -0,0 +1,257 @@
    +class SectionsNotExposed extends BrowserTestBase {
    

    Whu not subclass \Drupal\Tests\rest\Functional\ResourceTestBase?

  4. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/SectionsNotExposed.php
    @@ -0,0 +1,257 @@
    +   * (Sadly this cannot be computed automatically yet.)
    

    ?

  5. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/SectionsNotExposed.php
    @@ -0,0 +1,257 @@
    +    $contents = $response->getBody()->getContents();
    

    I think this might be the culprit.

    \Psr\Http\Message\StreamInterface::getContents()'s docs say:
    Returns the remaining contents in a string
    remaining only!

    This is a big WTF for sure.

    It's also why all REST/JSON:API test coverage uses (string) $response->getBody().

    And … that's another reason to use ResourceTestBase :)

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new11.88 KB
new14.98 KB
  1. I changed the title of the issue in #14 to reflect that it is get rid of all "sections". The sections exist in the override field but also in Entity View Displays third party settings. See testLayoutEntityDisplay().
  2. I assume this is 👍 for overriding defaultAccess() and not access(). Just checking to be sure.
  3. Changed to extend ResourceTestBase
  4. Remove/not need anymore, copy/paste error.
  5. Thanks I think that fixed. I still have 2 cases where we need the contents. But refactoring into method.

🤞 for tests passing on drupalci

Status: Needs review » Needs work

The last submitted patch, 25: 3028301-25.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new23.74 KB
new14.67 KB
  1. Stilling getting the NotEncodableValueException exception above.
  2. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/SectionsNotExposed.php
    @@ -0,0 +1,322 @@
    +    // @todo why does this fail? unrelated error?
    +    $this->assertCount(1, $this->node->get(OverridesSectionStorage::FIELD_NAME));
    +     */
    

    @tim.plunkett help me debug this and we think it might be related to #2985882: Workaround for "Call to a member function getLabel() after enabling layout_builder"

    For now I can't get this to work unless I clear the field cache. We can tell the field is actually there because the override gets stored in setup().

  3. Because of how \Drupal\Tests\rest\Functional\ResourceTestBase::provisionResource works I have spilt this into 2 test classes with a base class.
    This allows remove the test module.

Status: Needs review » Needs work

The last submitted patch, 27: 3028301-27.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new765 bytes
new14.65 KB
+++ b/core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php
@@ -0,0 +1,154 @@
+    return $this->serializer->decode((string) $response->getBody()->getContents(), static::$format);

Whoops I don't need the ->getContents().

kristen pol’s picture

Issue summary: View changes

Adding "how to test" to the issue summary per #12.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests
StatusFileSize
new6.33 KB
new14.37 KB

Not reviewing each interdiff, but responding to each comment, and then reviewing the entire patch:


#25:
  1. I don't quite understand your response. I think you might be saying that as of #14 it's just a normalizer for the display, not for the sections in the display. But my concern is actually that we're adding a normalizer at all.
  2. Indeed! 😀The issue summary already wonderfully describes why that is preferable (you did that in #8, well done!): it means that people have to go out of their way to expose layout information for now. Which means they also accept the consequences of changes in the storage and normalization representations.
  3. 👍
  4. 👍

#27:

  1. Nice!

#29: :)


Patch review:

  1. +++ b/core/modules/layout_builder/layout_builder.services.yml
    @@ -47,3 +47,10 @@ services:
    +  layout_builder.normalizer.layout_entity_display:
    +    class: Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer
    

    👎 This is still here, just like in #24.1. I still don't understand why.

    I should've read it better back in #24!

    👍This is overriding serializer.normalizer.config_entity to ensure we don't lock ourselves into that data structure either. To be honest, I had not yet considered the config entity aspect yet — I was only thinking about content entities.

    But given that the default layout for a given content entity type+bundle is stored in a config entity, and a content entity's "layout" field may contain an override of that default layout, and therefore both actually would expose the same data structure that is not something we want to ossify just yet, I think this makes perfect sense! 👏

    Until we have at least per-top-level key for config entities (if that ever happens, if that even makes sense), this is the only possible solution. 👍

  2. +++ b/core/modules/layout_builder/layout_builder.services.yml
    @@ -47,3 +47,10 @@ services:
    +      # Set the priority higher than the serializer.normalizer.config_entity normalizer, so that we do not replace it.
    ...
    +    arguments: ['@entity_type.manager', '@entity_type.repository', '@entity_field.manager']
    

    👎 ✅ Now this is my remaining concern for this service.

    The comment does not make sense to me ("so that we do not replace it" — huh?). And rather than duplicating all of its service dependencies, we should at minimum use parent: …, and preferably use decorates: ….

    Otherwise, any upstream change would need to be duplicated here. IOW: this introduces tight coupling we don't want or need.

    Done.

  3. +++ b/core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php
    @@ -0,0 +1,28 @@
    +/**
    + * Normalizes/denormalizes LayoutEntityDisplay objects into an array structure.
    + */
    +class LayoutEntityDisplayNormalizer extends ConfigEntityNormalizer {
    

    ✅ This is definitely ephemeral, so we should mark it as @internal. Done.

  4. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySections.php
    @@ -0,0 +1,65 @@
    +  public function setUp() {
    +    parent::setUp();
    +    $this->provisionResource([static::$format], ['basic_auth'], ['GET']);
    +  }
    
    +++ b/core/modules/layout_builder/tests/src/Functional/Rest/OverrideSections.php
    @@ -0,0 +1,153 @@
    +  public function setUp() {
    +    parent::setUp();
    +    $this->provisionResource([static::$format], ['basic_auth']);
    

    ✅ This is in both subclasses, so might as well do it in the base class. Done.

  5. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySections.php
    @@ -0,0 +1,65 @@
    +    // Assert the display has 1 section.
    +    $this->assertCount(1, $display->getThirdPartySetting('layout_builder', 'sections'));
    ...
    +    // Ensure the sections have been removed from third party settings.
    +    $this->assertEquals(['enabled' => TRUE, 'allow_custom' => TRUE], $response_data['third_party_settings']['layout_builder']);
    

    👍

  6. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php
    @@ -0,0 +1,154 @@
    +  protected function setUpAuthorization($method) {
    +    $permissions = array_keys($this->container->get('user.permissions')->getPermissions());
    +    // Give the test user all permissions on the site. There should be no
    +    // permission that gives the user access to layout sections.
    +    $this->account = $this->drupalCreateUser($permissions);
    +  }
    

    👏👏

  7. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/OverrideSections.php
    @@ -0,0 +1,153 @@
    +    // Make a GET request and ensure override field is not included.
    ...
    +    $this->assertArrayNotHasKey('layout_builder__layout', $patch_data);
    ...
    +    // Make a POST request with override field.
    +    $new_node['layout_builder__layout'] = [];
    ...
    +    $this->assertResourceErrorResponse(403, 'Access denied on creating field \'layout_builder__layout\'.', $response);
    ...
    +    // Make a PATCH request with the override field.
    +    $patch_data['title'][0]['value'] = 'This title will not save.';
    +    $patch_data['layout_builder__layout'] = [];
    ...
    +    $this->assertResourceErrorResponse(403, 'Access denied on updating field \'layout_builder__layout\'.', $response);
    +    // Ensure the title has not changed.
    +    $this->assertEquals('New and improved title', Node::load(1)->getTitle());
    

    👏👏

  8. Some whitespace, language and naming nits, which I fixed.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 31: 3028301-31.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tim.plunkett’s picture

+++ b/core/modules/layout_builder/layout_builder.services.yml
@@ -44,9 +44,8 @@ services:
+    parent: serializer.normalizer.config_entity
...
-    arguments: ['@entity_type.manager', '@entity_type.repository', '@entity_field.manager']

In order for this to work, we'd have to move this to LayoutBuilderServiceProvider and check for moduleExists('serialization')

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new15.06 KB
new2.1 KB
wim leers’s picture

Status: Needs review » Reviewed & tested by the community

👍

Sorry, I should have realized that!

xjm’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
    @@ -74,4 +76,11 @@ public function equals(FieldItemListInterface $list_to_compare) {
    +  public function defaultAccess($operation = 'view', AccountInterface $account = NULL) {
    +    return AccessResult::forbidden();
    +  }
    
    +++ b/core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php
    @@ -0,0 +1,30 @@
    +  protected static function getDataWithoutInternals(array $data) {
    +    $data = parent::getDataWithoutInternals($data);
    +    // Do not expose the actual layout sections in normalization.
    +    unset($data['third_party_settings']['layout_builder']['sections']);
    +    return $data;
    

    We should link the issues where we're discussing whether to add back normalization and how with an inline comment and an @todo.

  2. +++ b/core/modules/layout_builder/src/LayoutBuilderServiceProvider.php
    @@ -35,6 +37,13 @@ public function register(ContainerBuilder $container) {
    +    if (isset($modules['serialization'])) {
    +      $definition = (new ChildDefinition('serializer.normalizer.config_entity'))
    +        ->setClass(LayoutEntityDisplayNormalizer::class)
    +        // Priority must be higher than serializer.normalizer.config_entity.
    +        ->addTag('normalizer', ['priority' => 5]);
    +      $container->setDefinition('layout_builder.normalizer.layout_entity_display', $definition);
    

    Why must the priority be higher? Edit: My point, is the comment should say why.

  3. +++ b/core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php
    @@ -0,0 +1,30 @@
    +/**
    + * Normalizes/denormalizes LayoutEntityDisplay objects into an array structure.
    + *
    + * @internal
    + */
    

    Let's document why it's internal.

  4. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySections.php
    @@ -0,0 +1,58 @@
    +    // Ensure the sections have been removed from third party settings.
    

    Nit: "third-party settings".

    This comment also made it sound like section data was actually being deleted from a config entity. I think the comment should end with "...in the serialized data."

  5. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php
    @@ -0,0 +1,156 @@
    +      'title' => 'A node at rest will stay at rest.',
    
    +++ b/core/modules/layout_builder/tests/src/Functional/Rest/OverrideSections.php
    @@ -0,0 +1,153 @@
    +    $this->assertSame('A node at rest will stay at rest.', $get_data['title'][0]['value']);
    

    lol puns!

  6. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php
    @@ -0,0 +1,156 @@
    +    ]);
    +
    +
    +    $this->drupalGet('node/' . $this->node->id() . '/layout');
    ...
    +    $this->node = $this->nodeStorage->load($this->node->id());
    +
    +
    +    $this->drupalLogout();
    

    Double blank lines; these will cause a phpcs fail and make this patch uncommittable. :)

  7. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/LayoutRestTestBase.php
    @@ -0,0 +1,156 @@
    +    // Give the test user all permissions on the site. There should be no
    +    // permission that gives the user access to layout sections.
    

    For clarity, we probably should say "...no permission that gives the user access to layout sections over REST."

  8. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/OverrideSections.php
    @@ -0,0 +1,153 @@
    +    $this->assertEquals('On with the rest of the test.', $posted_node->getTitle());
    

    MORE puns.

xjm’s picture

Oh this also still needs its change record.

xjm’s picture

Issue tags: +Needs release note

Actually this probably needs to be mentioned in the release notes as well.

xjm’s picture

Issue tags: -Needs release note

Sorry, never mind about the release note, I forgot since the last time I reviewed this that currently we don't expose anything and this is just making it explicit. So just the CR. Thanks!

tim.plunkett’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record
StatusFileSize
new15.55 KB
new6.19 KB

#36
1) Done
2) Done, but opened #3031698: Consider making the default normalizers take a lower priority by default as well because this seems unwieldy.
3) Done
4) Fixed and expanded the test slightly
5) 😂
6) Fixed
7) Fixed
8) I love it

Also I changed the test classes to have a Test suffix.

Opened a CR https://www.drupal.org/node/3031697

xjm’s picture

  1. +++ b/core/modules/layout_builder/src/LayoutBuilderServiceProvider.php
    @@ -40,7 +40,8 @@ public function register(ContainerBuilder $container) {
    +        // Priority must be higher than serializer.normalizer.config_entity in
    +        // order to take precedence.
    
    diff --git a/core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php b/core/modules/layout_builder/src/Normalizer/LayoutEntityDisplayNormalizer.php
    index e7a83d0cbe..c4c7640471 100644
    

    Okay yes that's what a higher priority is by definition, but why must it take precedence?

  2. +++ b/core/modules/layout_builder/tests/src/Functional/Rest/EntityDisplaySectionsTest.php
    @@ -51,7 +51,10 @@ public function testLayoutEntityDisplay() {
    +    // Ensure the sections not present in the serialized data, but other Layout
    +    // Builder data is.
    

    There's a verb missing now.

tim.plunkett’s picture

StatusFileSize
new15.58 KB
new2.08 KB

Fixed

tedbow’s picture

Status: Needs review » Reviewed & tested by the community

Looks good!

  • xjm committed d885938 on 8.7.x
    Issue #3028301 by tedbow, tim.plunkett, Wim Leers, xjm: Do not expose to...
xjm’s picture

Status: Reviewed & tested by the community » Fixed

Committed to 8.7.x and published the change record. Thanks!

tedbow’s picture

@xjm thanks for committing.

@Wim Leers thanks for your help on this an suggesting not exposing the field right now.

@tim.plunkett @Kristen Pol thanks for the help too

Status: Fixed » Closed (fixed)

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