mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-17 07:10:12 +02:00
fix(security-classifier): close writer + delete tmp on download error
downloadFile() opens an fs.WriteStream to '<dest>.tmp.<pid>' and drives it from a fetch body reader, but if reader.read() or writer.write() throws mid-download the writer is never closed. That leaks an FD per failed attempt and leaves the half-written tmp on disk. A later retry can land in renameSync(tmp, dest) with a truncated TestSavantAI / DeBERTa ONNX file — which then loads but produces garbage classifier verdicts until the user manually nukes the models cache. Wrap the download loop in try/catch. On failure, destroy() the writer and unlink the tmp before rethrowing, so the next attempt starts from a clean slate.
This commit is contained in:
@@ -144,16 +144,24 @@ async function downloadFile(url: string, dest: string): Promise<void> {
|
||||
const writer = fs.createWriteStream(tmp);
|
||||
// @ts-ignore — Node stream compat
|
||||
const reader = res.body.getReader();
|
||||
let done = false;
|
||||
while (!done) {
|
||||
const chunk = await reader.read();
|
||||
if (chunk.done) { done = true; break; }
|
||||
writer.write(chunk.value);
|
||||
try {
|
||||
let done = false;
|
||||
while (!done) {
|
||||
const chunk = await reader.read();
|
||||
if (chunk.done) { done = true; break; }
|
||||
writer.write(chunk.value);
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
writer.end((err?: Error | null) => (err ? reject(err) : resolve()));
|
||||
});
|
||||
fs.renameSync(tmp, dest);
|
||||
} catch (err) {
|
||||
// Close the writer and drop the half-written tmp so we don't leak an FD
|
||||
// or ship a truncated model file to the renameSync path on retry.
|
||||
try { writer.destroy(); } catch { /* already destroyed */ }
|
||||
try { fs.unlinkSync(tmp); } catch { /* nothing to clean */ }
|
||||
throw err;
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
writer.end((err?: Error | null) => (err ? reject(err) : resolve()));
|
||||
});
|
||||
fs.renameSync(tmp, dest);
|
||||
}
|
||||
|
||||
async function ensureTestsavantStaged(onProgress?: (msg: string) => void): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user