feat: adapter-level Divi release lock, content-create and site status

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-30 02:04:49 +02:00
co-authored by Claude Opus 5.5
parent adfe0adfc2
commit c6a1996be6
12 changed files with 192 additions and 6 deletions
@@ -11,6 +11,8 @@ use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\ChangeLog\ChangeLog;
use LIT\MCP\Integrations\Divi\Pages\DiviContentComposer;
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
use LIT\MCP\Integrations\WordPress\Content\ContentCreateAbility;
use LIT\MCP\Integrations\WordPress\Content\NewDraft;
@@ -56,11 +58,12 @@ final class ContentCreateDiviTest extends TestCase
}
/** @return ContentComposer&MockInterface */
private function composer(bool $available = true, bool $writable = true): ContentComposer
private function composer(bool $available = true, bool $writable = true, ?WP_Error $refusal = null): ContentComposer
{
$composer = Mockery::mock(ContentComposer::class);
$composer->allows('available')->andReturn($available);
$composer->allows('writable')->andReturn($writable);
$composer->allows('refusal')->andReturn($refusal);
$composer->allows('check')->with('page', self::SECTIONS)->andReturn(null);
return $composer;
@@ -194,6 +197,16 @@ final class ContentCreateDiviTest extends TestCase
* Security M2: with the Divi group disabled or "nur lesen", or lit/divi-insert disabled, the
* divi input is refused before anything is created; content-create without divi keeps working.
*/
public function testLockedDiviRefusesBeforeTheDraftExists(): void
{
$refusal = (new ReleaseStatus(ReleaseState::Untested, '5.3.0'))->refusal();
Functions\expect('wp_insert_post')->never();
$result = $this->ability($this->composer(true, true, $refusal))->execute(self::INPUT);
self::assertToolError($result, 'divi_untested');
}
public function testDiviIsRefusedWhenDiviWritesAreSwitchedOff(): void
{
Functions\expect('wp_insert_post')->never();
@@ -224,6 +237,7 @@ final class ContentCreateDiviTest extends TestCase
$composer = Mockery::mock(ContentComposer::class);
$composer->allows('available')->andReturn(true);
$composer->allows('writable')->andReturn(true);
$composer->allows('refusal')->andReturn(null);
$composer->allows('check')->andReturn(Errors::invalidAttrPath(['divi[0].attrs.x' => 'unbekannt']));
$writer = Mockery::mock(PostWriter::class);
$writer->allows('prepare')->andReturn(Errors::invalidInput('ungültig', ['fields.role' => 'Pflichtfeld fehlt.']));
@@ -323,6 +337,11 @@ final class ContentCreateDiviTest extends TestCase
return true;
}
public function refusal(): ?WP_Error
{
return null;
}
public function check(string $postType, array $sections): ?WP_Error
{
return $this->real->check($postType, $sections);