Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Automattic\BlocksEngine\PhpTransformer\Css\CssRuleAnalyzer;
use Automattic\BlocksEngine\PhpTransformer\Css\CssSelectorMatcher;
use Automattic\BlocksEngine\PhpTransformer\Css\CssValueSplitter;
use Automattic\BlocksEngine\PhpTransformer\Path\ArtifactPath;
use DOMElement;
use InvalidArgumentException;

Expand Down Expand Up @@ -207,7 +208,7 @@ private static function assertFacts(array $layout, array $provenance, ?array $co
throw new InvalidArgumentException('Form layout graph provenance exceeds its limit.');
}
foreach ( $provenance as $fact ) {
if ( ! is_array($fact) || ! is_string($fact['source_path'] ?? null) || ! preg_match('~^(?!.*(?:^|/)\.\.(?:/|$))[A-Za-z0-9._/-]+$~', $fact['source_path']) || ! preg_match('/^[a-f0-9]{64}$/', $fact['source_sha256'] ?? '') || ! is_string($fact['selector'] ?? null) || '' === trim($fact['selector']) || strlen($fact['selector']) > 1024 || ! is_array($fact['properties'] ?? null) || array() === $fact['properties'] || count($fact['properties']) > count($properties) || array_filter($fact['properties'], static fn (mixed $property): bool => ! is_string($property) || ! in_array($property, $properties, true) || ! isset($layout[self::layoutKey($property)])) || ($condition !== null && $fact['condition'] !== $condition) || ($condition === null && ($fact['condition'] ?? null) !== null) ) {
if ( ! is_array($fact) || ! is_string($fact['source_path'] ?? null) || '' === ArtifactPath::safeRelativePath($fact['source_path']) || ArtifactPath::safeRelativePath($fact['source_path']) !== $fact['source_path'] || ! preg_match('/^[a-f0-9]{64}$/', $fact['source_sha256'] ?? '') || ! is_string($fact['selector'] ?? null) || '' === trim($fact['selector']) || strlen($fact['selector']) > 1024 || ! is_array($fact['properties'] ?? null) || array() === $fact['properties'] || count($fact['properties']) > count($properties) || array_filter($fact['properties'], static fn (mixed $property): bool => ! is_string($property) || ! in_array($property, $properties, true) || ! isset($layout[self::layoutKey($property)])) || ($condition !== null && $fact['condition'] !== $condition) || ($condition === null && ($fact['condition'] ?? null) !== null) ) {
throw new InvalidArgumentException('Form layout graph provenance is invalid.');
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use Automattic\BlocksEngine\PhpTransformer\Css\CssRuleAnalyzer;
use Automattic\BlocksEngine\PhpTransformer\Css\CssSelectorMatcher;
use Automattic\BlocksEngine\PhpTransformer\Path\ArtifactPath;
use Closure;
use DOMDocument;
use DOMElement;
Expand Down Expand Up @@ -170,7 +171,7 @@ private static function assertProvenance(array $provenance, array $styles, ?arra
{
if ( count($provenance) > self::MAX_PROVENANCE ) throw new InvalidArgumentException('Form presentation provenance exceeds its limit.');
foreach ( $provenance as $fact ) {
if ( ! is_array($fact) || ! is_string($fact['source_path'] ?? null) || ! preg_match('~^(?!.*(?:^|/)\.\.(?:/|$))[A-Za-z0-9._/-]+$~', $fact['source_path']) || ! preg_match('/^[a-f0-9]{64}$/', $fact['source_sha256'] ?? '') || ! is_string($fact['selector'] ?? null) || '' === trim($fact['selector']) || strlen($fact['selector']) > 1024 || ! is_array($fact['properties'] ?? null) || array() === $fact['properties'] || array_filter($fact['properties'], static fn (mixed $property): bool => ! is_string($property) || ! in_array($property, self::PROPERTIES, true) || ! isset($styles[self::key($property)])) || ($condition !== null && ($fact['condition'] ?? null) !== $condition) || ($condition === null && ($fact['condition'] ?? null) !== null) ) throw new InvalidArgumentException('Form presentation provenance is invalid.');
if ( ! is_array($fact) || ! is_string($fact['source_path'] ?? null) || '' === ArtifactPath::safeRelativePath($fact['source_path']) || ArtifactPath::safeRelativePath($fact['source_path']) !== $fact['source_path'] || ! preg_match('/^[a-f0-9]{64}$/', $fact['source_sha256'] ?? '') || ! is_string($fact['selector'] ?? null) || '' === trim($fact['selector']) || strlen($fact['selector']) > 1024 || ! is_array($fact['properties'] ?? null) || array() === $fact['properties'] || array_filter($fact['properties'], static fn (mixed $property): bool => ! is_string($property) || ! in_array($property, self::PROPERTIES, true) || ! isset($styles[self::key($property)])) || ($condition !== null && ($fact['condition'] ?? null) !== $condition) || ($condition === null && ($fact['condition'] ?? null) !== null) ) throw new InvalidArgumentException('Form presentation provenance is invalid.');
}
}

Expand Down
5 changes: 5 additions & 0 deletions php-transformer/tests/contract/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,11 @@ public function recognize(DOMElement $element, PatternContext $context): ?Patter
$projectedDeepGraph = $deepDeclaration['payload']['entities'][0]['layout_graph'] ?? array();
$projectedWidthNodes = array_values(array_filter($projectedDeepGraph['nodes'] ?? array(), static fn(array $node): bool => 'td' === ($node['source']['tag'] ?? null) && '33.333333333333%' === ($node['layout']['width'] ?? null)));
$assert(3 === count($projectedWidthNodes) && false === ($projectedDeepGraph['truncated'] ?? null), 'artifact compilation projects the complete deep percentage-width graph into generic/forms/v1.');
$safeProvenanceArtifact = (new ArtifactCompiler())->compile(array('entrypoint' => 'index.html', 'files' => array('index.html' => '<link rel="stylesheet" href="assets/form style.css">' . $layoutGraphHtml, 'assets/form style.css' => '.form{display:grid}')))->toArray();
$safeProvenanceDeclaration = current(array_filter($safeProvenanceArtifact['source_reports']['wordpress_site_plan']['runtime_declarations'] ?? array(), static fn(array $declaration): bool => 'forms' === ($declaration['type'] ?? null)));
$safeProvenanceGraph = $safeProvenanceDeclaration['payload']['entities'][0]['layout_graph'] ?? array();
$safeProvenanceNode = array_column($safeProvenanceGraph['nodes'] ?? array(), null, 'id')['form'] ?? array();
$assert('assets/form style.css' === ($safeProvenanceNode['provenance'][0]['source_path'] ?? null), 'artifact compilation accepts canonical stylesheet paths in emitted form layout provenance.');
$depthBoundaryHtml = '<form>' . str_repeat('<div>', 16) . '<input name="edge">' . str_repeat('</div>', 16) . '<button type="submit">Send</button></form>';
$depthOverflowHtml = '<form>' . str_repeat('<div>', 17) . '<input name="overflow">' . str_repeat('</div>', 17) . '<button type="submit">Send</button></form>';
$depthBoundaryGraph = (new HtmlTransformer())->transform($depthBoundaryHtml, array('static_css' => 'input{width:100%}'))->toArray()['fallbacks'][0]['layout_graph'] ?? array();
Expand Down
Loading