feat(storage): add verified offline MinIO migration pilot
This commit is contained in:
37
scripts/storage/tests/keys.test.mjs
Normal file
37
scripts/storage/tests/keys.test.mjs
Normal file
@@ -0,0 +1,37 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { validateKeys, MAX_OBJECT_BYTES, metadata } from '../s3.mjs';
|
||||
import { cleanupProbe, atomicJson } from '../s3.mjs';
|
||||
import { mkdtemp, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
test('accepts FEDEO keys, special characters, empty objects and size boundary', () => {
|
||||
validateKeys([{ Key: 'tenant/filesbyid/123/ä + %#.pdf', Size: 0 }, { Key: 'export.zip', Size: MAX_OBJECT_BYTES }]);
|
||||
});
|
||||
test('blocks lossy paths and file/directory collisions regardless of ordering', () => {
|
||||
for (const Key of ['/a', 'a/', 'a//b', 'a/../b', './a', 'a\\b', 'a\nb'])
|
||||
assert.throws(() => validateKeys([{ Key, Size: 1 }]));
|
||||
assert.throws(() => validateKeys([{ Key: 'a/b', Size: 1 }, { Key: 'a', Size: 1 }]));
|
||||
assert.throws(() => validateKeys([{ Key: 'a', Size: MAX_OBJECT_BYTES + 1 }]));
|
||||
});
|
||||
test('rejects encryption and nonportable attributes rather than dropping them', () => {
|
||||
for (const value of [{ ServerSideEncryption: 'AES256' }, { ObjectLockMode: 'GOVERNANCE' },
|
||||
{ StorageClass: 'GLACIER' }, { WebsiteRedirectLocation: '/other' }]) assert.throws(() => metadata(value));
|
||||
assert.deepEqual(metadata({ ContentType: 'application/pdf', Metadata: { custom: 'value' } }),
|
||||
{ ContentType: 'application/pdf', Metadata: { custom: 'value' } });
|
||||
});
|
||||
|
||||
test('interrupted contract cleanup deletes only its two journalled probe objects', async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'fedeo-probe-test-'));
|
||||
try {
|
||||
const path = join(directory, 'probe.json');
|
||||
const key = 'fedeo-contract-11111111-1111-1111-1111-111111111111/test';
|
||||
await atomicJson(path, { key });
|
||||
const inputs = [];
|
||||
await cleanupProbe({ send: async command => { inputs.push(command.input); return {}; } }, 'bucket', path);
|
||||
assert.deepEqual(inputs, [{ Bucket: 'bucket', Key: key }, { Bucket: 'bucket', Key: key + '.stream' }]);
|
||||
await atomicJson(path, { key: 'real-business-file.pdf' });
|
||||
await assert.rejects(cleanupProbe({ send: async () => { throw new Error('must not send'); } }, 'bucket', path), /Probejournal/);
|
||||
} finally { await rm(directory, { recursive: true, force: true }); }
|
||||
});
|
||||
Reference in New Issue
Block a user