From 2eefc85609be01baba6a3d233bf3386d2cf8c046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20DONNART?= Date: Mon, 16 Mar 2026 17:39:38 +0100 Subject: [PATCH 1/3] Handle single Contents element in ListObjectsV2 XML parsing Issue: CLDSRVCLT-12 --- src/commands/s3Extended/utils.ts | 2 +- tests/commands/s3Extended/utils.test.ts | 56 +++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/commands/s3Extended/utils.test.ts diff --git a/src/commands/s3Extended/utils.ts b/src/commands/s3Extended/utils.ts index 820139a9..aabd4740 100644 --- a/src/commands/s3Extended/utils.ts +++ b/src/commands/s3Extended/utils.ts @@ -75,7 +75,7 @@ export function parseListObjectsUserMetadataMiddleware(captured: { xml: string } // eslint-disable-next-line @typescript-eslint/no-explicit-any return (next: any) => async (args: any) => { const result = await next(args); - const parsed = new XMLParser().parse(captured.xml); + const parsed = new XMLParser({ isArray: name => name === 'Contents' }).parse(captured.xml); const xmlContents = parsed?.ListBucketResult?.Contents; if (result.output.Contents && xmlContents) { for (let i = 0; i < result.output.Contents.length; i++) { diff --git a/tests/commands/s3Extended/utils.test.ts b/tests/commands/s3Extended/utils.test.ts new file mode 100644 index 00000000..99f22ae6 --- /dev/null +++ b/tests/commands/s3Extended/utils.test.ts @@ -0,0 +1,56 @@ +import { parseListObjectsUserMetadataMiddleware } from '../../../src/commands/s3Extended/utils'; + +describe('parseListObjectsUserMetadataMiddleware', () => { + function buildXml(contents: Record[]): string { + const inner = contents.map(obj => `${ + Object.entries(obj).map(([k, v]) => `<${k}>${v}`).join('') + }`).join(''); + return `${inner}`; + } + + function createNext(output: unknown) { + return async () => ({ output }); + } + + it('should extract user metadata when XML contains a single Contents element', async () => { + const captured = { + xml: buildXml([ + { 'Key': 'obj1', 'x-amz-meta-foo': 'bar' }, + ]), + }; + + const middleware = parseListObjectsUserMetadataMiddleware(captured); + const result = await middleware(createNext({ + Contents: [{ Key: 'obj1' }], + }))({ request: {} }); + expect(result.output.Contents[0]['x-amz-meta-foo']).toBe('bar'); + }); + + it('should extract user metadata when XML contains multiple Contents elements', async () => { + const captured = { + xml: buildXml([ + { 'Key': 'obj1', 'x-amz-meta-foo': 'bar' }, + { 'Key': 'obj2', 'x-amz-meta-foo': 'baz' }, + ]), + }; + + const middleware = parseListObjectsUserMetadataMiddleware(captured); + const result = await middleware(createNext({ + Contents: [{ Key: 'obj1' }, { Key: 'obj2' }], + }))({ request: {} }); + expect(result.output.Contents[0]['x-amz-meta-foo']).toBe('bar'); + expect(result.output.Contents[1]['x-amz-meta-foo']).toBe('baz'); + }); + + it('should handle empty Contents gracefully', async () => { + const captured = { + xml: buildXml([]), + }; + + const middleware = parseListObjectsUserMetadataMiddleware(captured); + const result = await middleware(createNext({ + Contents: undefined, + }))({ request: {} }); + expect(result.output.Contents).toBeUndefined(); + }); +}); From 1d58dbb73e1eb6cc3f2537ea437d3d343e55c556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20DONNART?= Date: Tue, 17 Mar 2026 10:35:41 +0100 Subject: [PATCH 2/3] Add --experimental-vm-modules for Jest compatibility @smithy/node-http-handler v4.5.0 introduced a lazy dynamic import() for node:http (smithy-lang/smithy-typescript#1921). Jest runs tests in a Node.js vm sandbox which requires --experimental-vm-modules for dynamic imports on both Node 22 and 24. Issue: CLDSRVCLT-12 --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9dbe4797..95761157 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,10 @@ "build:generated:proxyBackbeatApis": "cd build/smithy/cloudserverProxyBackbeatApis/typescript-codegen && yarn install && yarn build", "build:wrapper": "tsc", "build": "yarn install && yarn clean:build && yarn build:smithy && yarn build:generated:backbeatRoutes && yarn build:generated:bucketQuota && yarn build:generated:proxyBackbeatApis && yarn build:wrapper", - "test": "jest", - "test:mongo-backend": "BACKEND_TYPE=mongo jest", - "test:metadata-backend": "BACKEND_TYPE=metadata jest", - "test:backbeat-apis": "BACKBEAT_SETUP=true yarn jest tests/testBackbeatProxyApis.test.ts", + "test": "NODE_OPTIONS='--experimental-vm-modules' jest", + "test:mongo-backend": "BACKEND_TYPE=mongo yarn test", + "test:metadata-backend": "BACKEND_TYPE=metadata yarn test", + "test:backbeat-apis": "BACKBEAT_SETUP=true yarn test -- tests/testBackbeatProxyApis.test.ts", "lint": "eslint src tests", "typecheck": "tsc --noEmit" }, From 995060da8bb763f9b12a2f431eca416296b2a6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20DONNART?= Date: Tue, 17 Mar 2026 09:07:45 +0100 Subject: [PATCH 3/3] Bump package.json to 1.0.7 Issue: CLDSRVCLT-12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 95761157..b993ed09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@scality/cloudserverclient", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=20" },