Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions lib/generic-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ async function validateAttachment(req) {
const malwareScanner = await cds.connect.to("malwareScanner")

// Set status to Scanning and commit before emitting event to prevent race conditions
cds.tx(
await cds.tx(
async () =>
await malwareScanner.updateStatus(target, keys, "Scanning"),
)
Expand Down Expand Up @@ -289,21 +289,6 @@ async function validateAttachmentSize(req, validateContentLength = false) {
}
})

cds.spawn(async () => {
try {
const AttachmentsSrv = await cds.connect.to("attachments")
await AttachmentsSrv.emit("AttachmentSizeExceeded", {
target: req.target.name,
keys: req.data.ID ? { ID: req.data.ID } : {},
filename: attachmentRef?.filename ?? "n/a",
fileSize: length,
maxFileSize,
})
} catch (err) {
LOG.error("Failed to emit AttachmentSizeExceeded", err)
}
})

req.reject({
status: 413,
message: "AttachmentSizeExceeded",
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/attachments-non-draft.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
waitForScanStatus,
newIncident,
waitForDeletion,
delay,
} = require("../utils/testUtils")
const { join, resolve } = cds.utils.path
const { createReadStream, readFileSync, statSync } = cds.utils.fs
Expand All @@ -19,6 +20,9 @@ describe("Tests for uploading/deleting and fetching attachments through API call
let log = test.log()
const { createAttachmentMetadata, uploadAttachmentContent } = createHelpers()

// Allow background operations (malware scan status updates) to complete before teardown
afterAll(() => delay(2000))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best Practices: Hardcoded delay(2000) is a fragile teardown strategy

Using a fixed 2-second sleep to wait for background operations (malware scan status updates) is non-deterministic: it will silently pass on fast machines and silently fail on slow ones or under load. The codebase already has a purpose-built waitForScanStatus utility that properly awaits the actual completion event with a timeout.

Consider replacing the blind delay with a proper awaitable hook that tracks pending background operations, or at minimum document what specific operations are expected to complete and the rationale for the chosen timeout value. If this test suite consistently triggers a scan, waitForScanStatus from testUtils should be used instead.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • βœ… Helpful comment
  • 🀷 Neutral
  • ❌ This comment is not helpful


it("Create new entity and ensuring nothing attachment related crashes", async () => {
const resCreate = await POST("/odata/v4/admin/Incidents", {
title: "New Incident",
Expand Down
5 changes: 4 additions & 1 deletion tests/unit/validateAttachmentMimeType.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ const { join } = cds.utils.path
const app = join(__dirname, "../incidents-app")
const { axios, POST, PUT, GET } = cds.test(app)
const { validateAttachmentMimeType } = require("../../lib/generic-handlers")
const { newIncident } = require("../utils/testUtils")
const { newIncident, delay } = require("../utils/testUtils")

describe("validateAttachmentMimeType - Content-Type header bypass security test", () => {
axios.defaults.auth = { username: "alice" }

// Allow background operations (malware scan status updates) to complete before teardown
afterAll(() => delay(2000))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best Practices: Hardcoded delay(2000) is a fragile teardown strategy

Same issue as in the integration test: a fixed 2-second sleep is non-deterministic and could either waste time or still race on heavily loaded CI runners. If the background operations being awaited are detectable events (e.g., AttachmentUploadRejected emissions from cds.spawn), the teardown should await those events explicitly rather than sleeping for an arbitrary duration.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • βœ… Helpful comment
  • 🀷 Neutral
  • ❌ This comment is not helpful


/**
* Security Test: Content-Type Header Bypass Attack
*
Expand Down
Loading