fix: keep release downloads on configured origin
Signed Release / release (push) Successful in 7m18s
Signed Release / release (push) Successful in 7m18s
This commit is contained in:
@@ -50,7 +50,6 @@ public class SystemUpdateService {
|
||||
private static final int MAX_RELEASE_HISTORY = 20;
|
||||
private static final int MAX_RELEASE_ASSETS = 32;
|
||||
private static final int MAX_ASSET_NAME_CHARS = 255;
|
||||
private static final int MAX_ASSET_URL_CHARS = 4_096;
|
||||
|
||||
private final UpdateProperties properties;
|
||||
private final ObjectMapper objectMapper;
|
||||
@@ -266,6 +265,16 @@ public class SystemUpdateService {
|
||||
+ encode(repository[1]) + "/releases" + suffix);
|
||||
}
|
||||
|
||||
private URI releaseAssetUri(String tag, String name) {
|
||||
String[] repository = properties.getRepository().split("/", 2);
|
||||
if (repository.length != 2 || repository[0].isBlank() || repository[1].isBlank()) {
|
||||
throw new ApiException(500, "更新仓库配置无效");
|
||||
}
|
||||
String base = properties.getGiteaBaseUrl().replaceAll("/+$", "");
|
||||
return URI.create(base + "/" + encode(repository[0]) + "/" + encode(repository[1])
|
||||
+ "/releases/download/" + encode(tag) + "/" + encode(name));
|
||||
}
|
||||
|
||||
private JsonNode fetchReleaseJson(URI uri) {
|
||||
HttpRequest.Builder builder = HttpRequest.newBuilder(uri)
|
||||
.timeout(Duration.ofSeconds(Math.max(1, properties.getRequestTimeoutSeconds())))
|
||||
@@ -327,15 +336,12 @@ public class SystemUpdateService {
|
||||
List<ReleaseAsset> assets = new ArrayList<>();
|
||||
for (JsonNode node : root.path("assets")) {
|
||||
String name = text(node, "name");
|
||||
String downloadUrl = text(node, "browser_download_url");
|
||||
if (name.isBlank() || name.length() > MAX_ASSET_NAME_CHARS
|
||||
|| downloadUrl.isBlank() || downloadUrl.length() > MAX_ASSET_URL_CHARS) {
|
||||
if (name.isBlank() || name.length() > MAX_ASSET_NAME_CHARS) {
|
||||
throw new ApiException(502, "Release 文件信息无效");
|
||||
}
|
||||
validateAssetUrl(downloadUrl);
|
||||
assets.add(new ReleaseAsset(
|
||||
name,
|
||||
downloadUrl,
|
||||
releaseAssetUri(tag, name).toString(),
|
||||
node.path("size").asLong(0)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@ class SystemUpdateServiceTest {
|
||||
void checksLatestGiteaReleaseAndRequiresSignedAssetSet() throws Exception {
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||
server.createContext("/api/v1/repos/awaioi/ERP/releases/latest", exchange -> {
|
||||
String origin = "http://127.0.0.1:" + exchange.getLocalAddress().getPort();
|
||||
byte[] body = ("""
|
||||
byte[] body = """
|
||||
{
|
||||
"tag_name": "v0.2.0",
|
||||
"body": "PostgreSQL production release",
|
||||
@@ -52,12 +51,12 @@ class SystemUpdateServiceTest {
|
||||
"prerelease": false,
|
||||
"published_at": "2026-08-03T10:00:00Z",
|
||||
"assets": [
|
||||
{"name":"kaidi-erp-0.2.0.tar.gz","browser_download_url":"%s/app","size":123},
|
||||
{"name":"SHA256SUMS","browser_download_url":"%s/sums","size":64},
|
||||
{"name":"SHA256SUMS.sig","browser_download_url":"%s/sig","size":64}
|
||||
{"name":"kaidi-erp-0.2.0.tar.gz","browser_download_url":"http://legacy.invalid/app","size":123},
|
||||
{"name":"SHA256SUMS","browser_download_url":"http://legacy.invalid/sums","size":64},
|
||||
{"name":"SHA256SUMS.sig","browser_download_url":"http://legacy.invalid/sig","size":64}
|
||||
]
|
||||
}
|
||||
""").formatted(origin, origin, origin).getBytes(StandardCharsets.UTF_8);
|
||||
""".getBytes(StandardCharsets.UTF_8);
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json");
|
||||
exchange.sendResponseHeaders(200, body.length);
|
||||
exchange.getResponseBody().write(body);
|
||||
@@ -75,6 +74,9 @@ class SystemUpdateServiceTest {
|
||||
assertThat(status.latestVersion()).isEqualTo("0.2.0");
|
||||
assertThat(status.assets()).extracting(SystemUpdateService.ReleaseAsset::name)
|
||||
.containsExactly("kaidi-erp-0.2.0.tar.gz", "SHA256SUMS", "SHA256SUMS.sig");
|
||||
assertThat(status.assets()).extracting(SystemUpdateService.ReleaseAsset::downloadUrl)
|
||||
.allMatch(url -> url.startsWith("http://127.0.0.1:" + server.getAddress().getPort()
|
||||
+ "/awaioi/ERP/releases/download/v0.2.0/"));
|
||||
} finally {
|
||||
server.stop(0);
|
||||
}
|
||||
@@ -198,7 +200,7 @@ class SystemUpdateServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsReleaseAssetsFromAnotherOrigin() throws Exception {
|
||||
void ignoresReleaseAssetOriginsAndBuildsTrustedDownloadUrls() throws Exception {
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||
server.createContext("/api/v1/repos/awaioi/ERP/releases/latest", exchange -> {
|
||||
byte[] body = """
|
||||
@@ -214,9 +216,11 @@ class SystemUpdateServiceTest {
|
||||
server.start();
|
||||
try {
|
||||
SystemUpdateService service = service(configuredProperties(server.getAddress().getPort()), "0.3.0");
|
||||
assertThatThrownBy(service::check)
|
||||
.isInstanceOf(ApiException.class)
|
||||
.hasMessageContaining("未受信任");
|
||||
SystemUpdateService.UpdateStatus status = service.check();
|
||||
|
||||
assertThat(status.assets()).extracting(SystemUpdateService.ReleaseAsset::downloadUrl)
|
||||
.allMatch(url -> url.startsWith("http://127.0.0.1:" + server.getAddress().getPort()
|
||||
+ "/awaioi/ERP/releases/download/v0.4.0/"));
|
||||
} finally {
|
||||
server.stop(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user