Repository navigation
feat(artifacts): read UnityFS AssetBundle containers - #7699
Conversation
inspect-artifact and extract-artifact now recognize the UnityFS signature and treat format versions 6 through 9 as containers. Header facts (format version, player/engine strings, declared size, dataflags, blocks-info bounds and the declared 16-byte data hash) are retained alongside a directory of CAB-* and .resS members. Member bytes stream on demand: only the blocks covering the requested member are read and decompressed with bounded expansion and cancellation. Bundles declaring asset-bundle encryption keep header facts and report unknown directory coverage. LZMA blocks-info reports unknown coverage; LZMA member reads fail as unavailable while the directory stays readable. Malformed counts, out-of-stream members and declared sizes beyond the file fail as format errors. UnityFS classifies by bytes in root detection, inventory graph construction and desktop inspection, which emits a unityfs-header fact. Validation: tsc --noEmit, oxlint (no new findings on touched files), 17 reader tests covering LZ4HC/uncompressed tables, blocks-info at end, format 6 without padding alignment, multi-block members, malformed input, unsupported compression, cancellation and abandoned streams; full artifacts/domain/conformance suites pass. Verified against one real YooAsset bundle (Unity 2021.3.32f1, format 8, LZ4HC): the streamed SerializedFile contained its managed assembly byte-identical to a UnityPy extraction. Other producer variants unverified.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
[Medium impact] The reviewed changes appear safe to merge, with both numbered findings addressed and no new blocking issue found. SummaryAdds standalone UnityFS format 6–8 inspection and extraction through the shared CLI/MCP workflows.
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[CLI or MCP input] --> B[Byte-based detection]
B --> C[UnityFS reader]
C --> D[Bounded header and directory parsing]
D --> E[Named members and source facts]
E --> F{Content supported?}
F -->|Yes| G[Bounded member stream]
G --> H[Hash or extract bytes]
F -->|No| I[Unavailable hash and unknown coverage]
Reviews (3) · Last reviewed commit: "fix(artifacts): preserve coverage author..." · Reviewed by Greptile |
# Conflicts: # src/application/BinaryTargetResolver.ts # src/artifacts/createArtifactReader.ts # src/artifacts/extraction/ArtifactExtraction.ts # src/artifacts/inventory/ArtifactGraphConstruction.ts # src/artifacts/inventory/reader.ts # src/domain/artifactGraph.ts # src/domain/liveBinaryTargetSummary.ts
… main Upstream morluto#7699 added the unityfs and unityfs-entry format_metadata kinds. The fork's exhaustive comparison table must decide each kind, and the fork's vocabulary test must list every target format. The container's fields come from its own bytes, so it is not compared. A member declares its source_path and raw node flags; its index and offset are layout, as for Node SEA members. The contract docs and the UnityFS guide name the compared fields.
Upstream morluto#7699 added the unityfs target format, so the vocabulary test's per-format fixtures must name it; without one the test no longer typechecks against main.
Problem and outcome
Standalone UnityFS AssetBundles were opaque artifacts. The existing CLI and MCP inspection/extraction workflows now enumerate and recover format 6–8 members without running Unity. Version 9 has a different block-table layout and remains unsupported.
Approach and contract
source_location: null).Executed validation
npm run check:fast,npm run docs:check, changed-file formatting and bounded single-thread typed lint passed. Final-head CI run 40656542039 passed, including all eight portable shards and CI required; Greptile review is 5/5 with no unresolved threads. Merged as e78ac1a.417d59522a998fdee9a9c2b29fe35f3063222457: atlas_test, banner_1 and char_118_yuki.ab have six raw members verified by independent UnityPy 1.24.2 SHA-256 and actual CLI/MCP extraction. atlas_test source SHA-256:61ee5afb5f5c64f0a4f65f039d09b2509198363e713423289c895067ac215177.94fab716cwas compared with the original reader on the same main (2b8fb387b, baseline mergefa5296412): 12 alternating completed inspect/extract/SHA/cleanup tasks over atlas_test and char_118_yuki.ab, three fresh-process repetitions per file/lane. Before → after: elapsed 4.99–6.06 → 5.11–6.05 s; CPU 6.52–7.11 → 6.73–7.10 s; sampled process-family RSS 260.5–282.0 → 262.2–280.0 MiB. Request+stdout estimates 3253/3305 → 3237/3289 tokens. First/repeat runs do not imply flushed OS caches; ranges overlap, so no general speedup is claimed.Verification scope excludes real Unity engine execution, version 9, decryption, SerializedFile object/texture decoding, and embedded-carrier discovery. Input hashes, extraction cleanup receipts, per-task elapsed/CPU/family-RSS and token estimates are retained locally; no binary fixtures or planning artifacts are committed.
Author readiness
Human owner: @blankym
Before merge
type(scope): outcome.