fix(openai): avoid full MSIX scans during version checks

Use the known MSIX archive offset to keep Windows Desktop version checks within the range download budget. Cover both architectures with a bounded-read regression test.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Zyy
2026-10-21 10:33:18 +08:00
co-authored by Codex
parent b8479b59db
commit 7a7a7ed6ad
2 changed files with 41 additions and 2 deletions
@@ -11,7 +11,11 @@ const MAX_CORE: u64 = 512 * 1024 * 1024;
const MAX_ASAR_PREFIX: u64 = 128 * 1024 * 1024;
pub fn read_windows<R: Read + Seek>(source: R, arch: &str) -> io::Result<ClientRelease> {
let mut zip = zip::ZipArchive::new(source).map_err(|_| invalid())?;
// MSIX 从文件起点开始,固定偏移避免自动探测扫描整包、耗尽 HTTP Range 下载预算
let config = zip::read::Config {
archive_offset: zip::read::ArchiveOffset::Known(0),
};
let mut zip = zip::ZipArchive::with_config(config, source).map_err(|_| invalid())?;
if zip.len() > 20_000 {
return Err(invalid());
}
@@ -6,7 +6,22 @@ use provider_openai::transport::profile::platform_release::{
xz::IndexedXz,
};
use serde_json::json;
use std::io::{Cursor, Read, Write};
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
// seek 不重置累计读取预算,用小体积夹具捕获整包扫描
struct ReadBudget<R>(io::Take<R>);
impl<R: Read> Read for ReadBudget<R> {
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
self.0.read(buffer)
}
}
impl<R: Seek> Seek for ReadBudget<R> {
fn seek(&mut self, position: SeekFrom) -> io::Result<u64> {
self.0.get_mut().seek(position)
}
}
fn core(windows: bool, arm: bool) -> Vec<u8> {
let mut bytes = vec![0; 8192];
@@ -115,6 +130,26 @@ fn windows_and_linux_read_versions_from_the_same_package_and_check_architecture(
assert!(read_linux(Cursor::new(deb(arm)), other).is_err());
}
}
#[test]
fn windows_reads_versions_within_budget_despite_large_unrelated_entries() {
for (arch, arm) in [("x86_64", false), ("arm64", true)] {
let bytes = zip(arm, &core(true, arm));
let expected = read_windows(Cursor::new(&bytes), arch).unwrap();
let mut archive = zip::ZipWriter::new_append(Cursor::new(bytes)).unwrap();
archive
.start_file(
"app/unrelated.bin",
zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Stored),
)
.unwrap();
io::copy(&mut io::repeat(0).take(2 * 1024 * 1024), &mut archive).unwrap();
let bytes = archive.finish().unwrap().into_inner();
let source = ReadBudget(Cursor::new(bytes).take(64 * 1024));
assert_eq!(read_windows(source, arch).unwrap(), expected);
}
}
#[test]
fn truncated_or_corrupt_archives_do_not_publish_versions() {
let zip = zip(false, &core(true, false));