Improve error handling

This commit is contained in:
tdurieux committed 2026-05-06 18:43:36 +03:00
1 parent aae6eae6eb
commit da78708b7b
16 files changed
+360 -49

No files matched your search

+19 -1
View File
@@ -11,6 +11,7 @@ import StorageBase, { FILE_TYPE } from "./Storage";
import FileModel from "../model/files/files.model";
import { IFile } from "../model/files/files.types";
import { createLogger, serializeError } from "../logger";
import AnonymousError from "../AnonymousError";
const logger = createLogger("fs");
@@ -62,7 +63,9 @@ export default class FileSystem extends StorageBase {
async write(
repoId: string,
p: string,
data: string | Readable
data: string | Readable,
_source?: string,
expectedSize?: number
): Promise<void> {
const fullPath = join(config.FOLDER, this.repoPath(repoId), p);
// Atomic write: stream into a sibling .tmp and only rename into place
@@ -98,6 +101,21 @@ export default class FileSystem extends StorageBase {
data.pipe(ws);
});
}
// Size guard: stat the tmp before renaming. A short read produces a
// truncated tmp file that we MUST NOT promote — accepting it would
// shadow the real content on every subsequent request. Allow >=
// expectedSize because Git LFS files resolve to content larger than
// the pointer's recorded size.
if (typeof expectedSize === "number" && expectedSize > 0) {
const stat = await fs.promises.stat(tmpPath);
if (stat.size < expectedSize) {
await fs.promises.rm(tmpPath, { force: true }).catch(() => undefined);
throw new AnonymousError("storage_write_size_mismatch", {
httpStatus: 502,
object: { path: p, expected: expectedSize, actual: stat.size },
});
}
}
await fs.promises.rename(tmpPath, fullPath);
} catch (err) {
logger.error("write failed", serializeError(err));