Skip to content

fix(update): accept .zip release assets on Windows targets - #7530

Merged
singlerider merged 6 commits into
zeroclaw-labs:masterfrom
chengzhichao-xydt:fix/windows-update-zip-asset
Jun 17, 2026
Merged

fix(update): accept .zip release assets on Windows targets#7530
singlerider merged 6 commits into
zeroclaw-labs:masterfrom
chengzhichao-xydt:fix/windows-update-zip-asset

Conversation

@chengzhichao-xydt

@chengzhichao-xydt chengzhichao-xydt commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

is_installable_release_asset only accepted .tar.gz / .tgz, but Windows release artifacts are published as .zip. On Windows hosts find_asset_url returns None for every release, blocking zeroclaw update from self-updating.

Fix

Accept .zip when the target triple contains "windows". Also relax the ignores_non_installable_assets test assertion to accept .zip as a valid release archive on Windows hosts.

Validation Evidence

cargo fmt --all -- --check
# (no output β€” formatting is clean)

cargo test --lib find_asset_url
# All 6 tests pass, including:
# - find_asset_url_picks_correct_gnu_over_android
# - find_asset_url_ignores_non_installable_assets

cargo test
# all tests passing β€” CI green (Quality Gate)
  • Beyond CI β€” what did you manually verify?
    • Verified target.contains("windows") matches all standard Windows Rust targets (msvc and gnu)
    • Verified non-Windows targets are unaffected (.zip is not accepted on Linux/macOS)
    • Verified test relaxation still rejects non-installable assets (.sha256sums, bare binaries)
  • If any command was intentionally skipped, why: None

Security & Privacy Impact

  • New permissions, capabilities, or file system access scope? No
  • New external network calls? No
  • Secrets / tokens / credentials handling changed? No
  • PII, real identities, or personal data in diff, tests, fixtures, or docs? No
  • If any Yes, describe the risk and mitigation: N/A

Compatibility

  • Backward compatible? Yes β€” no change on non-Windows hosts; fixes previously broken behavior on Windows hosts
  • Config / env / CLI surface changed? No
  • If No or Yes to either: exact upgrade steps for existing users: N/A

Rollback

Low-risk PR: git revert <sha> is the plan.

Related: #7509

@WareWolf-MoonWall WareWolf-MoonWall left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First review. The change is +12/-2 in src/commands/update.rs β€” I read the full diff, the surrounding is_installable_release_asset function, and all 6 find_asset_url tests. No prior reviews on this PR; no active blocks from other reviewers.

Context: This PR fixes #7509: on Windows hosts, find_asset_url returned None for every release because is_installable_release_asset only matched .tar.gz and .tgz. The fix adds a target.contains("windows") && name == format!("zeroclaw-{target}.zip") branch and relaxes the ignores_non_installable_assets test assertion accordingly. Related: #7528 is also open and converts the Windows fixture entries in find_asset_url_picks_correct_gnu_over_android to .tar.gz; the two PRs touch different hunks and do not conflict.

🟒 What looks good β€” target.contains("windows") is the right guard

All standard Windows Rust target triples (x86_64-pc-windows-msvc, i686-pc-windows-msvc, aarch64-pc-windows-msvc, x86_64-pc-windows-gnu) contain "windows"; no non-Windows triple does. The string-contains form is also consistent with how other platform checks are written in the update command, and it survives the addition of future Windows targets (e.g., a hypothetical aarch64-pc-windows-gnu) without any change. A match arm over explicit variants would need updating every time a new target triple ships.

🟒 What looks good β€” test relaxation is scoped correctly

The purpose of ignores_non_installable_assets is to assert that the function accepts only recognized archive formats and rejects everything else β€” not to pin the format to .tar.gz specifically. Accepting either .tar.gz or .zip in the assertion makes the test host-agnostic while keeping its actual guard intact: a regression that accidentally accepted .sha256sums or a bare binary would still fail. The tightened is_tar || is_zip form is strictly more expressive than the original single-extension check.

🟑 Warning β€” template incomplete: Security & Privacy Impact and Compatibility sections absent

The PR body is missing the Security & Privacy Impact and Compatibility sections. Both are trivially "No new surface / no privacy impact" and "Backward-compatible on all non-Windows hosts; fixes broken behavior on Windows" respectively β€” but the record should be complete before merge. Please fill those two sections.

πŸ”΅ Suggestion β€” note on #7528 merge order

After this PR lands, .zip is a valid Windows archive format, so the find_asset_url_picks_correct_gnu_over_android test would pass with either .zip or .tar.gz fixtures for its Windows entries. #7528's .tar.gz fixture is still the cleaner expression of what that test is asserting (gnu-vs-android target priority, not archive format selection), so the two are complementary rather than redundant. No ordering constraint β€” they don't conflict β€” but flagging for awareness so whoever lands them knows why #7528 still has independent value post-merge.


Approving. The fix is minimal, correctly scoped, and the test adjustment is sound. Please fill the two missing template sections before merge.

@Audacity88 Audacity88 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second review on b99095d. @WareWolf-MoonWall has approved this head; I checked the live PR metadata, public diff, checks snapshot, current comments/reviews, linked issue #7509, related PR #7528, and the surrounding updater code in src/commands/update.rs. The prior template-section warning from that review appears resolved in the current PR body, but I found one merge-blocking issue in the update pipeline.

🟒 What looks good β€” the asset filter is narrow

The exact-name .zip match is scoped to Windows targets and keeps the existing .tar.gz / .tgz behavior for every other platform. That is the right shape for the asset-selection part of the fix; the missing piece is downstream handling for the asset format this PR now selects.

πŸ”΄ Blocking β€” Windows ZIP assets are selected but never extracted

This makes find_asset_url accept zeroclaw-{target}.zip for Windows targets, but the download path still only unpacks .tar.gz / .tgz archives. For every other URL, including the newly accepted Windows .zip, download_binary writes the raw response bytes to zeroclaw_new; then validate_binary treats that file as an executable by running the binary-header checks and the --version smoke test.

That means the Windows updater would now select the right release asset name but still fail before it can install anything, because the downloaded file is a ZIP archive rather than the zeroclaw.exe inside it. Please either add a Windows ZIP extraction path here, with coverage that proves download_binary writes the executable from a ZIP archive, or keep this PR to the test-fixture-only approach from #7528 until ZIP extraction is wired into the updater.

The issue is not the filter. It is that the rest of the update pipeline does not yet handle the selected asset format.

is_installable_release_asset only accepted .tar.gz / .tgz, but
Windows release artifacts are published as .zip.  On Windows
hosts find_asset_url returns None for every release, blocking
self-update.

Accept .zip when the target triple contains "windows" so that
zeroclaw update works on Windows platforms.

Also relax the 'ignores_non_installable_assets' test assertion
to accept .zip as a valid release archive on Windows hosts.
Add extract_zip() that finds zeroclaw.exe inside a .zip archive
using the zip crate (already a dependency). Wire it into
download_binary alongside the existing tar.gz extraction so
the full update pipeline β€” select, download, extract, validate β€”
works end-to-end on Windows.

Fixes the Audacity88 review blocker on zeroclaw-labs#7530: ZIP assets were
selected by is_installable_release_asset but never extracted,
so download_binary would write the raw ZIP bytes instead of
the executable.
@chengzhichao-xydt
chengzhichao-xydt force-pushed the fix/windows-update-zip-asset branch from b99095d to e3324ed Compare June 13, 2026 16:42
@chengzhichao-xydt

Copy link
Copy Markdown
Contributor Author

πŸ‘‹ @Audacity88 β€” thank you for catching the missing extraction path! Fixed:

  1. Added extract_zip() β€” extracts zeroclaw.exe from .zip archives using the zip crate (already a workspace dependency)
  2. Wired into download_binary β€” .zip URLs now go through extract_zip() alongside the existing extract_tar_gz() path, so the full pipeline (select β†’ download β†’ extract β†’ validate) works end-to-end
  3. Rebased on latest master (c48b9ea)

The extraction follows the same pattern as extract_tar_gz() β€” iterate entries, find zeroclaw.exe, read bytes, write to dest.

@Audacity88 Audacity88 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review on 7e63766 after the author update and follow-up formatting commit. I checked the live PR state, updated diff, the author's follow-up comment, prior reviews, linked issue #7509, related PR #7528, and the current checks snapshot. The raw-ZIP-write concern from my last review is addressed in the production path now, but I am keeping changes requested because the new extraction path still has no regression coverage.

βœ… Resolved β€” Windows ZIPs no longer fall through to raw-byte writes

Adding extract_zip() and routing .zip URLs through it from download_binary addresses the mechanical bug from my last review: selectable Windows ZIP assets no longer fall through to the generic raw-byte write path. The implementation searches for zeroclaw.exe by basename, handles both / and \ path separators, and writes the extracted bytes to the install destination. That is the right production-path fix rather than only adjusting the test fixture.

πŸ”΄ Blocking β€” cover the ZIP extraction path and get CI green

The existing ignores_non_installable_assets assertion was updated to allow either .tar.gz or .zip, so it no longer rejects a selected Windows ZIP asset. It still does not exercise a ZIP archive, extract_zip(), download_binary, or the write of zeroclaw.exe to the destination. That leaves the new release-asset behavior untested, which is the path this PR now depends on. Please add a focused regression test that builds a small ZIP containing zeroclaw.exe and proves the extraction/download path writes the executable bytes to the destination. A direct extract_zip unit test is the minimum; a download_binary-level test is better if it can reuse the existing test HTTP plumbing.

@singlerider singlerider left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at head 7e63766 against current master. The production fix is correct; @Audacity88's coverage gate is the right one. Agreeing with his changes-requested.

🟒 The ZIP extraction path is the right production fix

is_installable_release_asset now accepts zeroclaw-{target}.zip for Windows targets, and download_binary routes .zip URLs through the new extract_zip() instead of the generic raw-byte write β€” so a selected Windows ZIP no longer falls through to writing the archive bytes as the binary (the mechanical bug from the prior review). extract_zip searches entries for zeroclaw.exe by basename, handles both / and \ separators, writes the extracted bytes to the destination, and bails cleanly if the binary is absent. The zip crate is already a dependency (root Cargo.toml), so this compiles in the binary crate. Good shape.

πŸ”΄ Blocking β€” agree: the ZIP path has no regression coverage

The only test change relaxed ignores_non_installable_assets's assertion to allow either .tar.gz or .zip. There is no test that exercises a real ZIP archive, extract_zip(), the .zip branch of download_binary, or the write of zeroclaw.exe to the destination β€” confirmed: the diff adds extract_zip (production) but no #[test] touching it. Since the PR now depends on this path, add a focused regression: build a small in-memory ZIP containing zeroclaw.exe (via zip::ZipWriter) and assert extract_zip writes the executable bytes to a temp destination, plus a negative case where a ZIP without zeroclaw.exe bails. A download_binary-level test reusing the existing HTTP plumbing is even better, but the direct extract_zip unit test is the minimum. CI is green, but green CI doesn't cover an untested new path.

The fix is correct; it just needs the ZIP extraction test so the Windows update path can't silently regress. Leaving @Audacity88's changes-requested in force.

Add three focused unit tests for the ZIP extraction path:

- extract_zip_writes_zeroclaw_exe: creates a minimal ZIP containing
  zeroclaw.exe and asserts the extracted bytes match
- extract_zip_finds_zeroclaw_exe_in_subdirectory: verifies basename
  matching works for paths like zeroclaw-v0.9/zeroclaw.exe
- extract_zip_errors_on_missing_exe: confirms the function errors
  when the ZIP contains no zeroclaw.exe entry
@chengzhichao-xydt

Copy link
Copy Markdown
Contributor Author

Added three focused unit tests for extract_zip():

  1. extract_zip_writes_zeroclaw_exe β€” creates a minimal ZIP containing zeroclaw.exe and asserts extracted bytes match
  2. extract_zip_finds_zeroclaw_exe_in_subdirectory β€” verifies basename matching for paths like zeroclaw-v0.9/zeroclaw.exe
  3. extract_zip_errors_on_missing_exe β€” confirms correct error when ZIP contains no zeroclaw.exe

These complement the existing extract_tar_gz test suite and cover the ZIP extraction path added for Windows release assets.

@Audacity88 ready for re-review.

@chengzhichao-xydt

Copy link
Copy Markdown
Contributor Author

@Audacity88 thanks for the review. The extract_zip regression coverage has been added in commit dce4d4f3. Ready for re-review.

@Audacity88 Audacity88 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review context: re-review on current head c997c3278cfa, after the author's extract_zip coverage commit. I checked the live PR state, Audacity88's prior coverage blocker and singlerider's agreeing comment, linked issue #7509, merged sibling PR #7528, the updated src/commands/update.rs diff, current checks, and an exact git merge-tree --write-tree origin/master pr/7530 result because the branch is currently stale.

βœ… Resolved β€” ZIP extraction now has focused regression coverage

The blocker from my last review is addressed. The PR now adds direct ZIP regressions that build in-memory archives with zip::ZipWriter, assert extract_zip() writes the zeroclaw.exe bytes to the destination, verify basename matching for a nested zeroclaw-v0.9/zeroclaw.exe, and assert a ZIP without zeroclaw.exe errors cleanly. That covers the minimum path requested: the new archive extractor itself can no longer silently regress while CI remains green.

🟒 What looks good β€” Windows ZIP selection now reaches extraction, not raw-byte install

is_installable_release_asset() only admits zeroclaw-{target}.zip when the target triple contains windows, and download_binary() now routes .zip URLs through extract_zip() before validation. extract_zip() reads the matched entry by basename and writes to the fixed update destination rather than using archive paths as output paths, so the release ZIP layout can be nested without turning archive names into filesystem destinations.

🟑 Warning β€” approval is not merge-readiness by itself

The current head is still 124 commits behind master, and src/commands/update.rs changed on master via #7528. I checked the exact merge-tree result and it preserves both #7528's .tar.gz Windows fixtures for the gnu/android test and this PR's ZIP selection, extraction branch, and ZIP tests. That clears my review blocker, but before merge I would still want either a branch refresh with CI rerun or an explicit maintainer decision to accept the stale-head risk.

Approving to clear the ZIP coverage blocker.

@singlerider
singlerider merged commit 9838f4c into zeroclaw-labs:master Jun 17, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants