desktop: in-app updates follow the server you installed from
CI & Build / Python lint (push) Successful in 3s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 4s
Android / Core and FFI clippy and tests (push) Skipped
Android / Kotlin + Rust (APK) (push) Skipped
Android / Build the server image (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 10s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 1m17s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 1m45s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
CI & Build / Build & push image (push) Successful in 40s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 4s
Android / Core and FFI clippy and tests (push) Skipped
Android / Kotlin + Rust (APK) (push) Skipped
Android / Build the server image (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 10s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 1m17s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 1m45s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
CI & Build / Build & push image (push) Successful in 40s
Milestone 325 step 6 (Scribe #3254). The server publishes its AppImage in the updater's own format at /api/client/linux-appimage/update.json: the ordering key as `version`, the signature, and an absolute download URL built on the host that was asked, so the token the updater attaches goes nowhere else. Unsigned platforms and a server with no AppImage 404. The desktop's update source is now Fabled-Git (and its channel) or one server: - `read_source` is the one reader. The installer's `install-server` marker feeds the `update_server` pref once per new value, exactly as the channel marker feeds its pref; tauri.conf.json's endpoint is never consulted. - From a server, the check and the download carry the sync link's token when the app is linked to that same server. Without one the update shows and says to link rather than offering a button that 401s. - A server with no build says so. A 404 is "up to date" only on the forge, where it means an unpublished channel. - Sync → App updates offers the source once there is a server to offer (the chosen one, or the linked one), and only shows the channel for the forge. The trust anchor does not move: whatever the source, the updater verifies the AppImage against the public key built into the app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -393,3 +393,32 @@ async def test_the_bytes_need_authentication_even_though_the_version_does_not(ap
|
||||
place(platform_id)
|
||||
resp = await app.test_client().get(f"/api/client/{platform_id}/download")
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
async def test_the_appimage_has_an_updater_manifest_built_from_the_same_build(app):
|
||||
"""Tauri's single-build form: the ordering key it compares, the signature it
|
||||
checks, and an absolute URL on the host that was asked."""
|
||||
place("linux-appimage", signature="sig-bytes")
|
||||
resp = await app.test_client().get(
|
||||
"/api/client/linux-appimage/update.json", headers={"Host": "notes.example.com"}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
body = await resp.get_json()
|
||||
assert body["version"] == code_for("linux-appimage")
|
||||
assert body["signature"] == "sig-bytes"
|
||||
assert body["url"] == "http://notes.example.com/api/client/linux-appimage/download"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platform_id", [p.id for p in PLATFORMS if not p.signed])
|
||||
async def test_an_unsigned_platform_has_no_updater_manifest(app, platform_id):
|
||||
"""No signature, nothing the updater could verify, so nothing to offer it."""
|
||||
place(platform_id)
|
||||
resp = await app.test_client().get(f"/api/client/{platform_id}/update.json")
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
async def test_a_server_without_the_appimage_404s_its_updater_manifest(app):
|
||||
"""The desktop turns this into "this server has no update to offer" rather than
|
||||
"up to date", so the 404 has to be there to turn."""
|
||||
resp = await app.test_client().get("/api/client/linux-appimage/update.json")
|
||||
assert resp.status_code == 404
|
||||
|
||||
Reference in New Issue
Block a user