[PR #2683] [MERGED] fix(artifacts): report malformed ZIP archives as format failures #5309

Closed
opened 2026-10-31 01:05:37 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2683
Author: @kaoru0822-kitauji
Created: 10/13/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/zip-format-failures


📝 Commits (6)

  • 8e938b5 fix(artifacts): report malformed ZIP archives as format failures
  • 289b495 test(artifacts): share the ZIP inventory failure assertion
  • 1c5446e Merge remote-tracking branch 'origin/main' into fix/zip-format-failures
  • 285e99e Merge remote-tracking branch 'origin/main' into fix/zip-format-failures
  • 24a1cb3 Merge remote-tracking branch 'origin/main' into fix/zip-format-failures
  • fa09692 Merge remote-tracking branch 'origin/main' into fix/zip-format-failures

📊 Changes

2 files changed (+124 additions, -27 deletions)

View changed files

📝 src/artifacts/ZipArtifactReader.ts (+79 -6)
📝 tests/boundary/filesystem/artifactZipIntegrity.test.ts (+45 -21)

📄 Description

Problem

rea inspect-artifact (and inventory_artifact / extract_artifact) on a truncated or corrupt ZIP/APK/JAR returned:

{"code":"artifact_operation_failed","message":"Artifact could not be read or written. Check file access and try again.","details":{"operation":"inspect_artifact","reason":"io"}}

The file is readable; the archive is malformed. The io reason gives the wrong advice and drops the reason.

Root cause

zip.js throws plain Errors for archive faults (End of central directory not found, File format is not recognized, Overlapping entry found, Invalid compressed data, Compression method not supported, …). ZipArtifactReader passed them through untyped, so translateArtifactFailure's fallback turned each one into ArtifactOperationError(…, "io") with no detail.

Fix

The fix is at the producing boundary, ZipArtifactReader. zip.js faults are matched against its exported ERR_* constants and converted into typed ArtifactReaderFailures:

  • format for structural and data corruption (EOCD/central directory/local header missing, bad format, overlapping or out-of-bounds entries, invalid CRC/compressed data/size, ambiguous archive)
  • unavailable for unsupported archive features (compression method, encryption method, encrypted central directory, split archives)

The typing covers all three paths an error can take: entry enumeration, the getData rejection, and the WritableStream abort. Corrupt-data errors reach the abort path first. Unrecognized errors (real filesystem I/O) are passed through unchanged.

After the fix:

{"message":"Artifact is invalid or has changed. Get a fresh copy and try again.","details":{"operation":"inspect_artifact","reason":"format","detail":"ZIP archive is malformed: End of central directory not found"}}

Other ZIP consumers (Flutter APK reader, JADX JAR probe, SAZ decoder) keep their own mapping. Flutter and JADX messages now embed the clearer ZIP archive is malformed: … text.

Validation

  • tests/boundary/filesystem/artifactZipIntegrity.test.ts: the overlapping, corrupt-member and truncated ZIP cases now assert reason: "format" plus the zip.js detail. These tests previously pinned io. A new case covers an unsupported compression method → unavailable.
  • npm run test:focused on all 52 test files that exercise ZIP/APK/SAZ/JADX/Flutter readers: 557 passed, 3 skipped.
  • npm run check:fast passes.
  • Manual CLI check: ran inspect-artifact on truncated PK\3\4, a bare EOCD signature and a cut-off ZIP before and after the change. identify-flutter-build still reports invalid_format.

Remaining

identify_flutter_build and SAZ decoding still classify every non-limit ZIP failure as malformed input, genuine I/O errors included. They could now use ArtifactReaderFailure.reason, but that changes their error contracts, so it is left for a separate change.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2683 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/zip-format-failures` --- ### 📝 Commits (6) - [`8e938b5`](https://github.com/morluto/rea/commit/8e938b5bda10c4bbdcc91e62200f695ca90079e4) fix(artifacts): report malformed ZIP archives as format failures - [`289b495`](https://github.com/morluto/rea/commit/289b495ee8fe2b2b91baf5bb5c6fcfaa3d69f273) test(artifacts): share the ZIP inventory failure assertion - [`1c5446e`](https://github.com/morluto/rea/commit/1c5446e3fb9b6307eb4b92c3a25b2830c4d6820f) Merge remote-tracking branch 'origin/main' into fix/zip-format-failures - [`285e99e`](https://github.com/morluto/rea/commit/285e99ef2c47a1386942ddc12e9a0056e04855fd) Merge remote-tracking branch 'origin/main' into fix/zip-format-failures - [`24a1cb3`](https://github.com/morluto/rea/commit/24a1cb3b80666452f37473f821ae77ab528d1160) Merge remote-tracking branch 'origin/main' into fix/zip-format-failures - [`fa09692`](https://github.com/morluto/rea/commit/fa09692a1c5d47eea52946bbd7db01adb9d2cf1c) Merge remote-tracking branch 'origin/main' into fix/zip-format-failures ### 📊 Changes **2 files changed** (+124 additions, -27 deletions) <details> <summary>View changed files</summary> 📝 `src/artifacts/ZipArtifactReader.ts` (+79 -6) 📝 `tests/boundary/filesystem/artifactZipIntegrity.test.ts` (+45 -21) </details> ### 📄 Description ## Problem `rea inspect-artifact` (and `inventory_artifact` / `extract_artifact`) on a truncated or corrupt ZIP/APK/JAR returned: ```json {"code":"artifact_operation_failed","message":"Artifact could not be read or written. Check file access and try again.","details":{"operation":"inspect_artifact","reason":"io"}} ``` The file is readable; the archive is malformed. The `io` reason gives the wrong advice and drops the reason. ## Root cause zip.js throws plain `Error`s for archive faults (`End of central directory not found`, `File format is not recognized`, `Overlapping entry found`, `Invalid compressed data`, `Compression method not supported`, …). `ZipArtifactReader` passed them through untyped, so `translateArtifactFailure`'s fallback turned each one into `ArtifactOperationError(…, "io")` with no detail. ## Fix The fix is at the producing boundary, `ZipArtifactReader`. zip.js faults are matched against its exported `ERR_*` constants and converted into typed `ArtifactReaderFailure`s: - `format` for structural and data corruption (EOCD/central directory/local header missing, bad format, overlapping or out-of-bounds entries, invalid CRC/compressed data/size, ambiguous archive) - `unavailable` for unsupported archive features (compression method, encryption method, encrypted central directory, split archives) The typing covers all three paths an error can take: entry enumeration, the `getData` rejection, and the `WritableStream` abort. Corrupt-data errors reach the abort path first. Unrecognized errors (real filesystem I/O) are passed through unchanged. After the fix: ```json {"message":"Artifact is invalid or has changed. Get a fresh copy and try again.","details":{"operation":"inspect_artifact","reason":"format","detail":"ZIP archive is malformed: End of central directory not found"}} ``` Other ZIP consumers (Flutter APK reader, JADX JAR probe, SAZ decoder) keep their own mapping. Flutter and JADX messages now embed the clearer `ZIP archive is malformed: …` text. ## Validation - `tests/boundary/filesystem/artifactZipIntegrity.test.ts`: the overlapping, corrupt-member and truncated ZIP cases now assert `reason: "format"` plus the zip.js detail. These tests previously pinned `io`. A new case covers an unsupported compression method → `unavailable`. - `npm run test:focused` on all 52 test files that exercise ZIP/APK/SAZ/JADX/Flutter readers: 557 passed, 3 skipped. - `npm run check:fast` passes. - Manual CLI check: ran `inspect-artifact` on truncated `PK\3\4`, a bare EOCD signature and a cut-off ZIP before and after the change. `identify-flutter-build` still reports `invalid_format`. ## Remaining `identify_flutter_build` and SAZ decoding still classify every non-limit ZIP failure as malformed input, genuine I/O errors included. They could now use `ArtifactReaderFailure.reason`, but that changes their error contracts, so it is left for a separate change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:05:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5309
No description provided.