From 3f36c101d0fc535aa8d4ae57ab046c0f0c442e7e Mon Sep 17 00:00:00 2001 From: Ken Lee Shu Ming Date: Thu, 6 Jun 2024 11:15:01 +0800 Subject: [PATCH] fix(submission): capture split error (#7360) * add test case when filename is null * fix: check for nullish filename --- .../__tests__/submission.service.spec.ts | 24 +++++++++++++++++++ .../__tests__/submission.utils.spec.ts | 10 ++++++++ .../modules/submission/submission.utils.ts | 16 ++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/app/modules/submission/__tests__/submission.service.spec.ts b/src/app/modules/submission/__tests__/submission.service.spec.ts index d97de25f05..6436e1a4dc 100644 --- a/src/app/modules/submission/__tests__/submission.service.spec.ts +++ b/src/app/modules/submission/__tests__/submission.service.spec.ts @@ -1914,6 +1914,30 @@ describe('submission.service', () => { expect(result._unsafeUnwrapErr()).toEqual(new InvalidFileExtensionError()) }) + it('should reject submissions when attachment responses are invalid', async () => { + // Special case where we found instances where the filename was not a string + // See https://www.notion.so/opengov/TypeError-Cannot-read-properties-of-undefined-reading-split-in-file-validation-js-6f4dcc17e6fc48319d8f7f0f997685c2?pvs=4 + // We can remove this test case when the issue is found and fixed + const processedResponse1 = generateNewAttachmentResponse({ + content: readFileSync('./__tests__/unit/backend/resources/invalid.py'), + filename: 'mock.jpg', + }) + + processedResponse1.filename = null as unknown as string + + // Omit attributes only present in processed fields + const response1 = omit(processedResponse1, [ + 'isVisible', + 'isUserVerified', + ]) + + const result = await SubmissionService.validateAttachments( + [response1], + FormResponseMode.Email, + ) + expect(result._unsafeUnwrapErr()).toEqual(new InvalidFileExtensionError()) + }) + it('should reject submissions when there are invalid file types in zip', async () => { const processedResponse1 = generateNewAttachmentResponse({ content: readFileSync( diff --git a/src/app/modules/submission/__tests__/submission.utils.spec.ts b/src/app/modules/submission/__tests__/submission.utils.spec.ts index 87f3876943..a594bfa240 100644 --- a/src/app/modules/submission/__tests__/submission.utils.spec.ts +++ b/src/app/modules/submission/__tests__/submission.utils.spec.ts @@ -111,6 +111,16 @@ describe('submission.utils', () => { }) describe('getInvalidFileExtensions', () => { + it('should throw error when filename is not a string', async () => { + // Special case where we found instances where the filename was not a string + // See https://www.notion.so/opengov/TypeError-Cannot-read-properties-of-undefined-reading-split-in-file-validation-js-6f4dcc17e6fc48319d8f7f0f997685c2?pvs=4 + // We can remove this test case when the issue is found and fixed + const promiseOutcome = getInvalidFileExtensions([ + { ...validSingleFile, filename: null as unknown as string }, + ]) + await expect(promiseOutcome).toReject() + }) + it('should return empty array when given a single valid file', async () => { const invalid = await getInvalidFileExtensions([validSingleFile]) expect(invalid).toEqual([]) diff --git a/src/app/modules/submission/submission.utils.ts b/src/app/modules/submission/submission.utils.ts index dcf7f104f8..1cb5fc5698 100644 --- a/src/app/modules/submission/submission.utils.ts +++ b/src/app/modules/submission/submission.utils.ts @@ -576,7 +576,21 @@ export const getInvalidFileExtensions = ( // Turn it into an array of promises that each resolve // to an array of file extensions that are invalid (if any) const promises = attachments.map((attachment) => { - const extension = FileValidation.getFileExtension(attachment.filename) + const { filename } = attachment + // Special case where we found instances where the filename was not a string + // See https://www.notion.so/opengov/TypeError-Cannot-read-properties-of-undefined-reading-split-in-file-validation-js-6f4dcc17e6fc48319d8f7f0f997685c2?pvs=4 + // We can remove this handling when the issue is found and fixed + if (filename == null) { + logger.error({ + message: 'A string is expected, but received null or undefined', + meta: { + action: 'getInvalidFileExtensions', + filename, + }, + }) + return Promise.reject(new Error('filename is required')) + } + const extension = FileValidation.getFileExtension(filename) if (FileValidation.isInvalidFileExtension(extension)) { return Promise.resolve([extension]) }