fix: surface partial S3 object deletion failures

This commit is contained in:
tdurieux
2026-09-06 09:18:32 +02:00
parent 4643e9f838
commit 5e84bfaa5b
3 changed files with 23 additions and 1 deletions
+1
View File
@@ -1,6 +1,7 @@
{
"ERRORS": {
"repository_job_cancelled": "The repository changed or was removed while processing.",
"storage_delete_failed": "Unable to remove cached files. Please try again later.",
"unknown_error": "Unknown error, contact the admin.",
"unreachable": "Anonymous GitHub is unreachable, contact the admin.",
"request_error": "Unable to download the file, check your connection or contact the admin.",
+7 -1
View File
@@ -102,7 +102,13 @@ export default class S3Storage extends StorageBase {
// nothing to remove
return;
}
await this.client(200000).deleteObjects(params);
const result = await this.client(200000).deleteObjects(params);
if (result.Errors?.length) {
throw new AnonymousError("storage_delete_failed", {
httpStatus: 502,
object: result.Errors,
});
}
if (data.IsTruncated) {
await this.rm(repoId, dir);
+15
View File
@@ -79,6 +79,21 @@ describe("production regressions", function () {
});
}
function s3(client) {
stub(config, "S3_BUCKET", "test");
const S3 = require("../src/core/storage/S3").default;
const storage = new S3(); storage.client = () => client; storage.repoPath = () => "repo";
return storage;
}
it("rejects S3 per-object deletion failures", async function () {
const storage = s3({
listObjectsV2: async () => ({ Contents: [{ Key: "repo/data" }] }),
deleteObjects: async () => ({ Errors: [{ Key: "repo/data", Code: "AccessDenied" }] }),
});
try { await storage.rm("repo", "data"); throw new Error("expected rejection"); }
catch (error) { expect(error.message).to.equal("storage_delete_failed"); }
});
for (const status of ["removing", "removed", "expiring", "expired"]) {
it(`ignores delayed downloads for ${status} repositories`, async function () {
stub(db, "connect", async () => {});