Directory

⚓ T358769 JsonSchemaValidator fails to validate pages where an array within an array is used
Page MenuHomePhabricator

JsonSchemaValidator fails to validate pages where an array within an array is used
Closed, ResolvedPublic2 Estimated Story Points

Description

On my local setup, the MediaWiki:GrowthExperimentsHomepage.json page cannot pass validation (using 53944021e580432ca28ae7fe4500b3f4b1837cb4 from the example repository). Its content is:

{
	"GEHomepageSuggestedEditsIntroLinks": {
		"create": "foo",
		"image": "bar"
	}
}

shell.php fiddling:

> \MediaWiki\MediaWikiServices::getInstance()->get('CommunityConfiguration.ProviderFactory')->newProvider('NewcomersHomepage')->loadValidConfiguration()->getErrors()
= [
    [
      "type" => "error",
      "message" => "communityconfiguration-schema-validation-error",
      "params" => [
        "GEHomepageSuggestedEditsIntroLinks",
        "Array value found, but an object is required",
        [
          "property" => "GEHomepageSuggestedEditsIntroLinks",
          "pointer" => "/GEHomepageSuggestedEditsIntroLinks",
          "message" => "Array value found, but an object is required",
          "constraint" => "type",
          "context" => 1,
        ],
      ],
    ],
  ]

>

Removing "type": "object" from the JSON schema makes the page to pass validation successfully.

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

Change 1007630 had a related patch set uploaded (by Urbanecm; author: Urbanecm):

[mediawiki/extensions/CommunityConfiguration@master] JsonSchemaValidator: Properly convert config into stdClass data

https://gerrit.wikimedia.org/r/1007630

Change 1007575 had a related patch set uploaded (by Urbanecm; author: Sergio Gimeno):

[mediawiki/extensions/CommunityConfiguration@master] WikiPageLoader: do not use FORCE_ASSOC when fetching config

https://gerrit.wikimedia.org/r/1007575

In a discussion in Slack, @Sgs said:

The issue is coming from the FormatJson::FORCE_ASSOC flag in \CommunityConfiguration\Store\WikiPage\Loader->fetchConfig() calls to

FormatJson::parse(). The flag converts all "type": "object" properties in the JSON schema to arrays. That “tampers” the data shape and makes it invalid. Tentative fix 1007575. There’s a second FORCE_ASSOC usage in ApiEdit.php that we might want to review.

Based on this advice (thanks Sergio!), I realized the issue actually is that (object)$config from the JsonSchemaValidator class does not work recursively, cf. https://stackoverflow.com/questions/19272011/how-to-convert-an-array-into-an-object-using-stdclass. This can be fixed by writing our own conversion logic (for array -> stdClass) and using that before the validation.

While this would still force us to have an array as the top level data type, I think that makes absolute sense (everything that's not a single variable provider will need to start with an object either way). Staying with array also means less changes.

Based on the above, I uploaded https://gerrit.wikimedia.org/r/c/mediawiki/extensions/CommunityConfiguration/+/1007630.

Urbanecm_WMF triaged this task as High priority.
Urbanecm_WMF set the point value for this task to 2.

Change 1007575 abandoned by Sergio Gimeno:

[mediawiki/extensions/CommunityConfiguration@master] WikiPageLoader: do not use FORCE_ASSOC when fetching config

Reason:

Solved in I91aa8808307c36abb393574a85c4c6883028ce42

https://gerrit.wikimedia.org/r/1007575

Change 1007630 merged by jenkins-bot:

[mediawiki/extensions/CommunityConfiguration@master] JsonSchemaValidator: Properly convert config into stdClass data

https://gerrit.wikimedia.org/r/1007630

> $s = \MediaWiki\MediaWikiServices::getInstance()->get('CommunityConfiguration.ProviderFactory')->newProvider('NewcomersHomepage')->loadValidConfiguration()
= StatusValue {#7074
    +value: [
      "GEHomepageSuggestedEditsIntroLinks" => [
        "create" => "foo",
        "image" => "bar",
      ],
    ],
    +success: [],
    +successCount: 0,
    +failCount: 0,
    +statusData: null,
  }

> $s->isOK()
= true

> $s->getErrors()
= []

> $s->getValue()
= [
    "GEHomepageSuggestedEditsIntroLinks" => [
      "create" => "foo",
      "image" => "bar",
    ],
  ]

>

It works now! :)