fix(updater): Paket-Adresse aus Tag und Dateiname bauen, Version 1.0.2
Gitea meldet browser_download_url hinter dem TLS-Proxy mit http://, der Updater lehnte die Adresse ab und fand kein Update. Die Adresse wird jetzt aus dem geprüften Tag und dem Dateinamen gebaut; release-check.sh prüft genauso. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
b2759fba73
commit
c8648d5263
@@ -25,8 +25,10 @@ latest="$(curl -fsS "$gitea/api/v1/repos/$repo/releases/latest")" \
|
|||||||
tag="$(jq -r .tag_name <<<"$latest")"
|
tag="$(jq -r .tag_name <<<"$latest")"
|
||||||
[[ "$tag" == "v$version" ]] || fail "releases/latest liefert '$tag', erwartet v$version"
|
[[ "$tag" == "v$version" ]] || fail "releases/latest liefert '$tag', erwartet v$version"
|
||||||
|
|
||||||
zip_url="$(jq -r --arg n "$name" '.assets[] | select(.name == $n) | .browser_download_url' <<<"$latest")"
|
# The address is built like GiteaUpdater builds it: Gitea behind a TLS proxy reports http:// in browser_download_url.
|
||||||
[[ "$zip_url" == "$gitea/$repo/releases/download/"* ]] || fail "Asset-URL fehlt oder liegt woanders: '$zip_url'"
|
[[ "$(jq -r --arg n "$name" '[.assets[] | select(.name == $n)] | length' <<<"$latest")" == "1" ]] \
|
||||||
|
|| fail "Das Release hat kein Asset $name"
|
||||||
|
zip_url="$gitea/$repo/releases/download/$tag/$name"
|
||||||
|
|
||||||
work="$(mktemp -d)"
|
work="$(mktemp -d)"
|
||||||
trap 'rm -rf "$work"' EXIT
|
trap 'rm -rf "$work"' EXIT
|
||||||
|
|||||||
+6
-3
@@ -4,7 +4,7 @@ Tags: mcp, ai, divi, pods, oauth
|
|||||||
Requires at least: 6.9
|
Requires at least: 6.9
|
||||||
Tested up to: 7.1
|
Tested up to: 7.1
|
||||||
Requires PHP: 8.1
|
Requires PHP: 8.1
|
||||||
Stable tag: 1.0.1
|
Stable tag: 1.0.2
|
||||||
License: GPL-2.0-or-later
|
License: GPL-2.0-or-later
|
||||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
|
||||||
@@ -200,8 +200,8 @@ Bibliothekseintrags.
|
|||||||
Neue Versionen erscheinen als Release auf git.loosen-it.de; WordPress zeigt sie unter Plugins und Dashboard →
|
Neue Versionen erscheinen als Release auf git.loosen-it.de; WordPress zeigt sie unter Plugins und Dashboard →
|
||||||
Aktualisierungen an wie jedes andere Plugin. Automatisch einspielen lässt sich ein Update mit dem Schalter
|
Aktualisierungen an wie jedes andere Plugin. Automatisch einspielen lässt sich ein Update mit dem Schalter
|
||||||
„Automatische Updates aktivieren“ in der Plugin-Liste. Ein Update ersetzt den Plugin-Ordner; ein Entwicklungs-
|
„Automatische Updates aktivieren“ in der Plugin-Liste. Ein Update ersetzt den Plugin-Ordner; ein Entwicklungs-
|
||||||
Checkout mit .git-Ordner bekommt deshalb kein Update angeboten. Versionen vor 1.0.1 kennen diesen
|
Checkout mit .git-Ordner bekommt deshalb kein Update angeboten. Versionen vor 1.0.2 kennen diesen
|
||||||
Weg nicht: der Wechsel auf 1.0.1 ist einmalig von Hand (ZIP hochladen), danach läuft es über WordPress.
|
Weg nicht: der Wechsel auf 1.0.2 ist einmalig von Hand (ZIP hochladen), danach läuft es über WordPress.
|
||||||
|
|
||||||
== Divi-Freigabe ==
|
== Divi-Freigabe ==
|
||||||
|
|
||||||
@@ -209,6 +209,9 @@ LIT MCP schreibt nur mit Divi-Versionen, die für diese Plugin-Version geprüft
|
|||||||
|
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.0.2 =
|
||||||
|
* Behebt: 1.0.1 fand keine Updates, weil Gitea die Download-Adresse mit http:// meldet. Die Adresse des Pakets wird jetzt selbst aus Tag und Dateiname gebaut. Der Wechsel auf 1.0.2 ist einmalig von Hand.
|
||||||
|
|
||||||
= 1.0.1 =
|
= 1.0.1 =
|
||||||
* Updates über WordPress: Das neueste Release von git.loosen-it.de erscheint als Plugin-Update (Update URI); automatisches Einspielen über den Schalter in der Plugin-Liste. Der Wechsel auf 1.0.1 ist einmalig von Hand. (Version 1.0.0 wurde nie ausgeliefert.)
|
* Updates über WordPress: Das neueste Release von git.loosen-it.de erscheint als Plugin-Update (Update URI); automatisches Einspielen über den Schalter in der Plugin-Liste. Der Wechsel auf 1.0.1 ist einmalig von Hand. (Version 1.0.0 wurde nie ausgeliefert.)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ defined('ABSPATH') || exit;
|
|||||||
*/
|
*/
|
||||||
final class Plugin
|
final class Plugin
|
||||||
{
|
{
|
||||||
public const VERSION = '1.0.1';
|
public const VERSION = '1.0.2';
|
||||||
|
|
||||||
private static string $pluginFile = '';
|
private static string $pluginFile = '';
|
||||||
private static ?SettingsPage $settingsPage = null;
|
private static ?SettingsPage $settingsPage = null;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ defined('ABSPATH') || exit;
|
|||||||
* Gitea host, so WordPress asks the filter update_plugins_<host> (about every 12 hours, which is also the only
|
* Gitea host, so WordPress asks the filter update_plugins_<host> (about every 12 hours, which is also the only
|
||||||
* caching needed). The release carries the ZIP as asset wp-lit-mcp-<version>.zip.
|
* caching needed). The release carries the ZIP as asset wp-lit-mcp-<version>.zip.
|
||||||
*
|
*
|
||||||
* shortcut: no signature – a package is trusted as far as the repository's release downloads and TLS are, so whoever
|
* shortcut: no signature – the package is trusted as far as the repository's release downloads and TLS are, so whoever
|
||||||
* can publish a release there ships code to every site that updates. Public release assets only (WordPress downloads
|
* can publish a release there ships code to every site that updates. Public release assets only (WordPress downloads
|
||||||
* without credentials). Add a signature checked before unpacking (key outside Gitea) before the plugin runs on sites
|
* without credentials). Add a signature checked before unpacking (key outside Gitea) before the plugin runs on sites
|
||||||
* you do not control.
|
* you do not control.
|
||||||
@@ -90,7 +90,7 @@ final class GiteaUpdater
|
|||||||
}
|
}
|
||||||
|
|
||||||
$version = $match[1];
|
$version = $match[1];
|
||||||
$package = self::packageUrl((array) ($body['assets'] ?? []), $version);
|
$package = self::packageUrl((array) ($body['assets'] ?? []), $tag, $version);
|
||||||
if ($package === null) {
|
if ($package === null) {
|
||||||
return self::failed(
|
return self::failed(
|
||||||
sprintf('release %s has no asset %s-%s.zip in the repository', $tag, self::SLUG, $version)
|
sprintf('release %s has no asset %s-%s.zip in the repository', $tag, self::SLUG, $version)
|
||||||
@@ -101,21 +101,18 @@ final class GiteaUpdater
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ZIP asset of this version, only from the repository's release downloads: the trust boundary of the update.
|
* The ZIP of this version – its address is built here from the checked tag and the file name, not taken from the
|
||||||
|
* answer: Gitea behind a TLS proxy reports http:// (its ROOT_URL), and a URL from the answer would be a second
|
||||||
|
* trust boundary. The asset only has to exist.
|
||||||
*
|
*
|
||||||
* @param array<array-key, mixed> $assets
|
* @param array<array-key, mixed> $assets
|
||||||
*/
|
*/
|
||||||
private static function packageUrl(array $assets, string $version): ?string
|
private static function packageUrl(array $assets, string $tag, string $version): ?string
|
||||||
{
|
{
|
||||||
|
$zipName = self::SLUG . '-' . $version . '.zip';
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
if (! is_array($asset)) {
|
if (is_array($asset) && ($asset['name'] ?? '') === $zipName) {
|
||||||
continue;
|
return self::RELEASE_DOWNLOADS . rawurlencode($tag) . '/' . $zipName;
|
||||||
}
|
|
||||||
|
|
||||||
$url = (string) ($asset['browser_download_url'] ?? '');
|
|
||||||
$isZip = ($asset['name'] ?? '') === self::SLUG . '-' . $version . '.zip';
|
|
||||||
if ($isZip && str_starts_with($url, self::RELEASE_DOWNLOADS)) {
|
|
||||||
return $url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,28 @@ final class GiteaUpdaterTest extends TestCase
|
|||||||
self::assertSame('', $this->log());
|
self::assertSame('', $this->log());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @dataProvider reportedAddresses */
|
||||||
|
public function testPackageAddressIsBuiltHereNotTakenFromTheAnswer(string $reported): void
|
||||||
|
{
|
||||||
|
$this->givenRelease(200, self::releaseBody('v1.0.0', self::ZIP_NAME, $reported));
|
||||||
|
|
||||||
|
$update = $this->updater()->offer(false, [], self::BASENAME);
|
||||||
|
|
||||||
|
self::assertSame(self::ZIP, $update['package']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<string, array{string}> */
|
||||||
|
public static function reportedAddresses(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'http, as Gitea behind a TLS proxy reports it' => [
|
||||||
|
'http://' . GiteaUpdater::HOST . '/janniclas.loosen/WP-LIT-MCP/releases/download/v1.0.0/'
|
||||||
|
. self::ZIP_NAME,
|
||||||
|
],
|
||||||
|
'another host' => ['https://evil.example/' . self::ZIP_NAME],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function testOtherPluginsAreLeftAlone(): void
|
public function testOtherPluginsAreLeftAlone(): void
|
||||||
{
|
{
|
||||||
Functions\expect('wp_remote_get')->never();
|
Functions\expect('wp_remote_get')->never();
|
||||||
@@ -104,8 +126,6 @@ final class GiteaUpdaterTest extends TestCase
|
|||||||
/** @return array<string, array{string}> */
|
/** @return array<string, array{string}> */
|
||||||
public static function unusableReleases(): array
|
public static function unusableReleases(): array
|
||||||
{
|
{
|
||||||
$foreign = 'https://evil.example/releases/download/v1.0.0/' . self::ZIP_NAME;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'no JSON' => ['<html>'],
|
'no JSON' => ['<html>'],
|
||||||
'tag is no version' => [self::releaseBody('latest', self::ZIP_NAME, self::ZIP)],
|
'tag is no version' => [self::releaseBody('latest', self::ZIP_NAME, self::ZIP)],
|
||||||
@@ -113,10 +133,7 @@ final class GiteaUpdaterTest extends TestCase
|
|||||||
'tag with trailing newline' => [self::releaseBody("v1.0.0\n", self::ZIP_NAME, self::ZIP)],
|
'tag with trailing newline' => [self::releaseBody("v1.0.0\n", self::ZIP_NAME, self::ZIP)],
|
||||||
'asset missing' => [self::releaseBody('v1.0.0', 'other.zip', self::ZIP)],
|
'asset missing' => [self::releaseBody('v1.0.0', 'other.zip', self::ZIP)],
|
||||||
'release without assets' => ['{"tag_name":"v1.0.0"}'],
|
'release without assets' => ['{"tag_name":"v1.0.0"}'],
|
||||||
'package from a foreign host' => [self::releaseBody('v1.0.0', self::ZIP_NAME, $foreign)],
|
'asset of another version' => [self::releaseBody('v1.0.0', 'wp-lit-mcp-0.9.0.zip', self::ZIP)],
|
||||||
'package outside the release downloads' => [
|
|
||||||
self::releaseBody('v1.0.0', self::ZIP_NAME, 'https://' . GiteaUpdater::HOST . '/other/repo/x.zip'),
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
/**
|
/**
|
||||||
* Plugin Name: WP-LIT-MCP
|
* Plugin Name: WP-LIT-MCP
|
||||||
* Description: MCP-Server für WordPress, Divi 5 und Pods – mit OAuth für KI-Assistenten.
|
* Description: MCP-Server für WordPress, Divi 5 und Pods – mit OAuth für KI-Assistenten.
|
||||||
* Version: 1.0.1
|
* Version: 1.0.2
|
||||||
* Update URI: https://git.loosen-it.de/janniclas.loosen/WP-LIT-MCP
|
* Update URI: https://git.loosen-it.de/janniclas.loosen/WP-LIT-MCP
|
||||||
* Requires at least: 6.9
|
* Requires at least: 6.9
|
||||||
* Requires PHP: 8.1
|
* Requires PHP: 8.1
|
||||||
|
|||||||
Reference in New Issue
Block a user