Prepare auto updates

This commit is contained in:
Jan-Niclas Loosen
2026-11-04 13:51:01 +01:00
parent a066d47bfd
commit 3337a63c5d
15 changed files with 784 additions and 16 deletions
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Updater;
use LIT\MCP\Updater\PackageSignature;
use PHPUnit\Framework\TestCase;
final class PackageSignatureTest extends TestCase
{
private string $zip = '';
private string $secretKey = '';
private PackageSignature $signature;
protected function setUp(): void
{
$pair = sodium_crypto_sign_keypair();
$this->secretKey = sodium_crypto_sign_secretkey($pair);
$this->signature = new PackageSignature(base64_encode(sodium_crypto_sign_publickey($pair)));
$this->zip = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-sig');
file_put_contents($this->zip, 'zip bytes');
}
protected function tearDown(): void
{
unlink($this->zip);
}
public function testASignatureOverNameAndContentVerifies(): void
{
$signature = $this->sign('wp-lit-mcp-1.0.0.zip');
self::assertTrue($this->signature->verifies('wp-lit-mcp-1.0.0.zip', $this->zip, $signature));
}
public function testAnotherAssetNameDoesNotVerify(): void
{
$signature = $this->sign('wp-lit-mcp-1.0.0.zip');
self::assertFalse($this->signature->verifies('wp-lit-mcp-1.0.1.zip', $this->zip, $signature));
}
public function testChangedContentDoesNotVerify(): void
{
$signature = $this->sign('x.zip');
file_put_contents($this->zip, 'changed bytes');
self::assertFalse($this->signature->verifies('x.zip', $this->zip, $signature));
}
public function testAnotherKeyDoesNotVerify(): void
{
$foreign = new PackageSignature(base64_encode(sodium_crypto_sign_publickey(sodium_crypto_sign_keypair())));
self::assertFalse($foreign->verifies('x.zip', $this->zip, $this->sign('x.zip')));
}
/** @dataProvider malformedInput */
public function testMalformedInputFailsClosed(string $signature, string $publicKey, string $zipPath): void
{
$subject = new PackageSignature($publicKey === 'real' ? $this->realKey() : $publicKey);
self::assertFalse($subject->verifies('x.zip', $zipPath === 'zip' ? $this->zip : $zipPath, $signature));
}
/** @return array<string, array{string, string, string}> */
public static function malformedInput(): array
{
return [
'signature is no base64' => ['not base64 !!', 'real', 'zip'],
'signature is empty' => ['', 'real', 'zip'],
'signature has the wrong length' => [base64_encode('short'), 'real', 'zip'],
'no key configured' => ['AAAA', '', 'zip'],
'key has the wrong length' => ['AAAA', base64_encode('short'), 'zip'],
'file is missing' => ['AAAA', 'real', '/nonexistent/x.zip'],
];
}
private function sign(string $assetName): string
{
$message = PackageSignature::message($assetName, $this->zip);
return base64_encode(sodium_crypto_sign_detached($message, $this->secretKey));
}
private function realKey(): string
{
return base64_encode(sodium_crypto_sign_publickey(sodium_crypto_sign_keypair()));
}
}