Problem/Motivation

Patternkit's TokenValidationDataPreProcessor bypasses JSON Schema format validation for Drupal token values (e.g., [site:name]) by calling $schema->setFormat(NULL) on the Swaggest Schema object. This is correct behavior for tokens, but the mutation is permanent: it modifies the cached Schema object in place.

SchemaFactory stores compiled schemas in static class properties ($schemasCache and $decodedSchemaCache). Static properties persist for the lifetime of the PHP process. In PHP-FPM environments, worker processes handle many requests. Once a single request triggers the token bypass on a format-constrained field (e.g., format: hostname), the format constraint is removed from the cached Schema object for all subsequent requests handled by that worker.

This means invalid values that should fail format validation silently pass. A field declared as format: hostname will accept any string, including completely invalid hostnames, after any prior request validated a token in the same field.

Steps to reproduce

  1. Enable Patternkit with a pattern that has a format: hostname (or format: uri, etc.) field.
  2. Place a block using this pattern and enter a Drupal token value (e.g., [site:name]) in the format-constrained field. Save the block. Server-side validation passes (correct).
  3. In a subsequent request handled by the same PHP-FPM worker, place another block of the same pattern type and enter an invalid value like not_a_valid___hostname in the format-constrained field.
  4. Expected: server-side validation rejects the value.
  5. Actual: the value is accepted because the format constraint was removed by step 2.

This is non-deterministic in production because PHP-FPM assigns requests to workers unpredictably. The bug may appear intermittently depending on which worker handles the request and whether a token was previously validated in the same field on that worker.

Proposed resolution

Convert SchemaFactory's static caches to instance properties. Drupal's dependency injection container creates a fresh SchemaFactory instance per request, so instance-scoped caches are naturally cleared between requests. Schema caching within a single request is preserved: repeated createInstance() calls with the same schema string still return the cached instance.

This also changes SchemaFactory::clearCache() from a static method to an instance method. There are no known callers of this method outside of tests.

Scope note

Within a single request, if two blocks using the same schema are validated and the first contains a token in a format-constrained field, the setFormat(NULL) mutation still affects the second block's validation within that request. This is mitigated by client-side JSON Editor enforcement (which blocks invalid values before form submission) and is an uncommon editorial scenario. A follow-up issue can address within-request isolation if needed.

Remaining tasks

  • Review and test the merge request.

User interface changes

None.

Introduced terminology

None.

API changes

SchemaFactory::clearCache() changes from a static method to an instance method. Callers must update from SchemaFactory::clearCache() to $schemaFactory->clearCache(). This method is not part of the module's public API and is intended for test isolation.

Data model changes

None.

Release notes snippet

Fixed a bug where SchemaFactory's static schema cache allowed format validation bypass (applied for Drupal token values) to persist across PHP-FPM requests, causing format constraints like hostname and uri to be silently skipped for subsequent requests on the same worker process. Schema caches are now instance-scoped, preventing cross-request mutation.

Issue fork patternkit-3605768

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

slucero created an issue. See original summary.

slucero’s picture

Status: Active » Needs review

  • slucero committed 68105fe1 on 9.1.x
    fix: #3605768 Convert SchemaFactory static caches to instance properties
    
slucero’s picture

Status: Needs review » Fixed

This is adequately covered by automated tests and difficult to manually test, so I've merged the MR.

Merged for inclusion in the 9.1.3 release.
See #3542304: Patternkit 9.1.3 Release Plan.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

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