Test coverage to prove `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` disallows garbage values

Created on 14 May 2025, about 2 months ago

Overview

Unlike for the block component source plugin (see 📌 `BlockComponent::validateComponentInput()` allows garbage to pile up Active ), no garbage values are AFAICT allowed for the sdc and js component sources.

This is thanks to GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput() calling

$this->componentValidator->validateProps($resolvedInputValues, $this->getSdcPlugin());

which would complain about unused props.

… or so I think 😅

Proposed resolution

Add test coverage to prove that the SDC + JS component sources are unaffected.

User interface changes

None.

📌 Task
Status

Active

Version

0.0

Component

Component sources

Created by

🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @wim leers
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇮🇳India Akhil Babu Chengannur

    Could you please give an example for 'garbage value'?

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    An SDC with the following in its *.component.yml:

    props:
      type: object
      required:
        - heading
      properties:
        heading:
          type: string
          title: Heading
          examples:
            - blabla
    

    … yet the explicit input it receives is not

    heading: "something"
    

    but

    heading: "something"
    foo: :"bar"
    

    IOW: some key-value pairs that are not expected by the SDC!

  • 🇮🇳India Akhil Babu Chengannur

    Thanks @wim leers🙏. I just tested this using the 'Heading' SDC, by adding an extra property 'textUnwanted' when making a curl request to the endpoint /xb/api/v0/layout/xb_page/5 and the changes were successfully saved. There were no validation errors regarding the unexpected prop

    curl --location 'https://starshot.ddev.site/xb/api/v0/layout/xb_page/5' \
    --header 'accept: */*' \
    --header 'accept-language: en-US,en-GB;q=0.9,en;q=0.8' \
    --header 'content-type: application/json' \
    --header 'origin: https://starshot.ddev.site' \
    --header 'priority: u=1, i' \
    --header 'referer: https://starshot.ddev.site/xb/xb_page/5/editor/component/fdc18261-ef6e-41bd-bdba-99ecc72bf359' \
    --header 'sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"' \
    --header 'sec-ch-ua-mobile: ?0' \
    --header 'sec-ch-ua-platform: "Linux"' \
    --header 'sec-fetch-dest: empty' \
    --header 'sec-fetch-mode: cors' \
    --header 'sec-fetch-site: same-origin' \
    --header 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36' \
    --header 'x-csrf-token: PIqRn04kuCGgm5leY3w_pc0Oq9ZGv0mzWXds0SE7cmg' \
    --header 'Cookie: SSESS1a128ff57fee5bd2b5663cea7bd52db5=n4epfmoesptq7m91dcj6skrvtl' \
    --data '{
      "layout": [
        {
          "nodeType": "region",
          "id": "content",
          "name": "Content",
          "components": [
            {
              "slots": [],
              "nodeType": "component",
              "type": "sdc.experience_builder.heading",
              "uuid": "fdc18261-ef6e-41bd-bdba-99ecc72bf359"
            }
          ]
        }
      ],
      "model": {
        "fdc18261-ef6e-41bd-bdba-99ecc72bf359": {
          "name": "Heading",
          "resolved": {
            "text": "A heading element new text",
            "style": "primary",
            "element": "h1",
            "textUnwanted": "An unwanted heading" // Invalid prop
          },
          "source": {
            "text": {
              "expression": "ℹ︎string␟value",
              "sourceType": "static:field_item:string",
              "value": [
                {
                  "value": "A heading element new text"
                }
              ]
            },
            "textUnwanted": { // Invalid prop
              "expression": "ℹ︎string␟value",
              "sourceType": "static:field_item:string",
              "value": [
                {
                  "value": "An unwanted heading"
                }
              ]
            },
            "style": {
              "expression": "ℹ︎list_string␟value",
              "sourceType": "static:field_item:list_string",
              "value": [
                {
                  "value": "primary"
                }
              ],
              "sourceTypeSettings": {
                "storage": {
                  "allowed_values": [
                    {
                      "value": "primary",
                      "label": "primary"
                    },
                    {
                      "value": "secondary",
                      "label": "secondary"
                    }
                  ]
                }
              }
            },
            "element": {
              "expression": "ℹ︎list_string␟value",
              "sourceType": "static:field_item:list_string",
              "value": [
                {
                  "value": "h1"
                }
              ],
              "sourceTypeSettings": {
                "storage": {
                  "allowed_values": [
                    {
                      "value": "div",
                      "label": "div"
                    },
                    {
                      "value": "h1",
                      "label": "h1"
                    },
                    {
                      "value": "h2",
                      "label": "h2"
                    },
                    {
                      "value": "h3",
                      "label": "h3"
                    },
                    {
                      "value": "h4",
                      "label": "h4"
                    },
                    {
                      "value": "h5",
                      "label": "h5"
                    },
                    {
                      "value": "h6",
                      "label": "h6"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "entity_form_fields": {
        "langcode[0][value]": "en",
        "revision_log[0][value]": "",
        "title[0][value]": "Untitled page",
        "path[0][alias]": "",
        "path[0][source]": "/page/5",
        "path[0][langcode]": "en",
        "image[media_library_selection]": "",
        "description[0][value]": ""
      }
    }'

    Just to confirm, does this mean validateComponentInput() currently allows unexpected properties (i.e., garbage values) for SDCs?

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Just to confirm, does this mean validateComponentInput() currently allows unexpected properties (i.e., garbage values) for SDCs?

    Indeed it does 😭

    Matching the title of 📌 `BlockComponent::validateComponentInput()` allows garbage to pile up Active then. 😭

    Updated issue summary with an adjusted proposed resolution.

    Credited you for the valuable research you've already done here, @akhil babu! 🙏

  • Pipeline finished with Failed
    about 2 months ago
    Total: 472s
    #498827
  • Pipeline finished with Failed
    about 2 months ago
    Total: 793s
    #498841
  • 🇮🇳India Akhil Babu Chengannur

    Thanks @wim leers. I have updated GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput() and added a check for unexpected props.

    However, no exception was thrown for the curl request mentioned in #5, and the heading component was still added to the canvas. The expected error only appeared when publishing the page (Because ValidComponentTree constratint was invoked)
    Shouldn't the error have been thrown at the time of the request?

    I also tried to validate 'missing' props but that resulted in many test failures as some props are not always part of user input (Like 'attribute' prop in sdc.experience_builder.my-hero component)

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Production build 0.71.5 2024