mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
Findings from a Codex (gpt-6.1-sol, xhigh) review of v0.2.4..HEAD, each verified in the code before fixing: - high: ticker symbols reached cache file paths unchecked, so a symbol like `../../REPORT` read (and deleted, if unparseable) .json files outside the cache, reachable through MCP get_quotes. resolve_symbol now accepts only ticker characters, and cache keys are encoded as single safe path components. - high: sync decided before downloading and replaced the database without rechecking; an import that landed meanwhile was erased. It now rechecks the local state before installing, and idx-mcp runs ownership_sync exclusively with ownership reads. - replaces_sqlite_sha256 never downgrades history: the client requires the rebuild to keep at least the local release count, and the publisher lists a replaced build only then. - cache writes are atomic (temp file + rename), so concurrent readers never see, and delete, a partial entry. - idx-mcp caps symbols (20, deduplicated) and limits, and runs at most 4 tool calls at once. - each Yahoo client gets its own cookie jar, paired with its crumb. - ZIP entries (XLSX, KSEI archives) are read with a 256 MiB bound; non-ASCII archive dates and huge percentages are parse errors instead of panics or overflow. - agent-smoke --keep deletes every copied agent config, not only auth files. CLI goldens unchanged; the MCP tool golden changes only to state the new caps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34 lines
1.1 KiB
Rust
34 lines
1.1 KiB
Rust
pub mod archive;
|
|
pub mod db;
|
|
pub mod entities;
|
|
pub mod graph;
|
|
pub mod parser;
|
|
pub mod remote;
|
|
pub mod search;
|
|
pub mod snapshot;
|
|
pub mod types;
|
|
pub mod xlsx;
|
|
|
|
use std::io::Read;
|
|
|
|
use crate::error::IdxError;
|
|
|
|
/// Largest decompressed ZIP entry read into memory. Real IDX worksheets and
|
|
/// KSEI TXT archives are tens of MB; this bounds a hostile "zip bomb".
|
|
const MAX_ZIP_ENTRY_BYTES: u64 = 256 * 1024 * 1024;
|
|
|
|
/// Reads one decompressed ZIP entry as UTF-8, failing past the size limit.
|
|
pub(crate) fn read_zip_entry_bounded(entry: impl Read, what: &str) -> Result<String, IdxError> {
|
|
let mut bytes = Vec::new();
|
|
entry
|
|
.take(MAX_ZIP_ENTRY_BYTES + 1)
|
|
.read_to_end(&mut bytes)
|
|
.map_err(|e| IdxError::ParseError(format!("failed to read {what}: {e}")))?;
|
|
if bytes.len() as u64 > MAX_ZIP_ENTRY_BYTES {
|
|
return Err(IdxError::ParseError(format!(
|
|
"{what} expands beyond {MAX_ZIP_ENTRY_BYTES} bytes"
|
|
)));
|
|
}
|
|
String::from_utf8(bytes)
|
|
.map_err(|e| IdxError::ParseError(format!("failed to decode {what}: {e}")))
|
|
}
|