From 2fe6a90d856a8d80dd89bc6d51b3488aef8c0c60 Mon Sep 17 00:00:00 2001 From: interlinkglobal Date: Sat, 8 Aug 2026 13:59:53 +0200 Subject: [PATCH 1/2] Fix release installer verification --- src/computer_agent/updater.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/computer_agent/updater.py b/src/computer_agent/updater.py index bceb35c..953b94c 100644 --- a/src/computer_agent/updater.py +++ b/src/computer_agent/updater.py @@ -22,7 +22,7 @@ ) LATEST_RELEASE_URL = "https://api.github.com/repos/interlinkglobal/Interly/releases/latest" INSTALLER_NAME = "InterlySetup-x64.exe" -MAX_INSTALLER_BYTES = 200 * 1024 * 1024 +MAX_INSTALLER_BYTES = 512 * 1024 * 1024 def installed_commit() -> str | None: @@ -163,10 +163,10 @@ def latest_release_installer() -> tuple[str, str, str]: raise RuntimeError("The latest release has no Windows installer.") url = str(asset.get("browser_download_url", "")) digest = str(asset.get("digest", "")) - expected_prefix = "https://github.com/interlinkglobal/Interly/releases/download/" - if not url.startswith(expected_prefix) or not digest.startswith("sha256:"): + expected_prefix = "https://github.com/interlinkglobal/interly/releases/download/" + if not url.casefold().startswith(expected_prefix) or not digest.casefold().startswith("sha256:"): raise RuntimeError("The release installer could not be verified.") - return version, url, digest.removeprefix("sha256:").casefold() + return version, url, digest.split(":", 1)[1].casefold() def download_release_installer(url: str, expected_digest: str) -> Path: From e813ab0f0b1c515eeefc28c1346915226297c05d Mon Sep 17 00:00:00 2001 From: interlinkglobal Date: Sat, 8 Aug 2026 14:00:20 +0200 Subject: [PATCH 2/2] Cover canonical release URL casing --- tests/test_updater.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/test_updater.py b/tests/test_updater.py index a4c8273..a0eb27d 100644 --- a/tests/test_updater.py +++ b/tests/test_updater.py @@ -4,6 +4,7 @@ from unittest.mock import patch from computer_agent.updater import ( + MAX_INSTALLER_BYTES, UPDATE_BRANCH, digest_file, installed_commit, @@ -17,6 +18,10 @@ def test_pipx_update_branch_is_main() -> None: assert UPDATE_BRANCH == "main" +def test_installer_size_limit_allows_current_windows_bundle() -> None: + assert MAX_INSTALLER_BYTES >= 400 * 1024 * 1024 + + @patch("computer_agent.updater.distribution") def test_installed_commit_reads_pip_vcs_metadata(metadata: object) -> None: metadata.return_value.read_text.return_value = json.dumps( @@ -103,7 +108,7 @@ def test_standalone_falls_back_to_verified_release_when_winget_cannot_find_packa run.return_value = SimpleNamespace(returncode=1, stdout="", stderr="No package found") release.return_value = ( "0.6.1", - "https://github.com/interlinkglobal/Interly/releases/download/v0.6.1/InterlySetup-x64.exe", + "https://github.com/interlinkglobal/interly/releases/download/v0.6.1/InterlySetup-x64.exe", "ab" * 32, ) download.return_value = "C:/Temp/InterlySetup-update-x64.exe" @@ -127,13 +132,13 @@ def test_standalone_falls_back_to_verified_release_when_winget_cannot_find_packa @patch("computer_agent.updater.httpx.get") def test_latest_release_requires_official_installer_and_sha256(get: object) -> None: get.return_value.json.return_value = { - "tag_name": "v0.6.0", + "tag_name": "0.6.0", "assets": [ { "name": "InterlySetup-x64.exe", "browser_download_url": ( - "https://github.com/interlinkglobal/Interly/releases/download/" - "v0.6.0/InterlySetup-x64.exe" + "https://github.com/interlinkglobal/interly/releases/download/" + "0.6.0/InterlySetup-x64.exe" ), "digest": f"sha256:{'ab' * 32}", } @@ -142,7 +147,7 @@ def test_latest_release_requires_official_installer_and_sha256(get: object) -> N assert latest_release_installer() == ( "0.6.0", - "https://github.com/interlinkglobal/Interly/releases/download/v0.6.0/InterlySetup-x64.exe", + "https://github.com/interlinkglobal/interly/releases/download/0.6.0/InterlySetup-x64.exe", "ab" * 32, )