test(server): storage slice-1 review follow-ups — mirror s3-replica probe decrypt, all-encrypted seed without key, test-route 401

This commit is contained in:
jubnl
2026-08-20 13:33:24 +02:00
parent 8fd6c0495d
commit 28ae8f3959
3 changed files with 62 additions and 0 deletions
@@ -109,6 +109,9 @@ describe('Storage admin e2e (real auth + admin guard + managed guard + temp SQLi
// class-level (JwtAuthGuard + AdminGuard on the controller), not re-added
// per handler where a future handler could forget them.
expect((await request(server).put('/api/admin/storage').send({ backends: [], categories: {} })).status).toBe(401);
expect(
(await request(server).post('/api/admin/storage/test').send({ backend: { name: 'x', type: 'local', options: { root: '/tmp' } } })).status,
).toBe(401);
});
it('STORE2E-002 403 for a non-admin', async () => {
@@ -320,4 +320,36 @@ describe('StorageAdminService.testBackend', () => {
}),
).rejects.toThrow("re-enter the secret 'secretAccessKey' for 'ghost'");
});
it('STORADM-025 a mirror with a stored s3 replica decrypts the enc:v1: secret for the probe', async () => {
const goodRoot = makeTmpDir();
const { service, uploadsRoot } = makeService();
service.applyConfig(configWith(uploadsRoot, {
backends: [
{ name: 'good-local', type: 'local', options: { root: goodRoot } },
{
name: 'off-box',
type: 's3',
options: { ...S3_OPTIONS, endpoint: 'http://127.0.0.1:1', retries: 0, timeoutMs: 200 },
},
],
categories: {},
}));
// applyConfig encrypted the secret at rest — the snapshot the mirror
// expansion reads holds ciphertext, so this probe exercises the full
// snapshot → decryptBackendSecrets → ephemeral S3Driver chain.
expect(readRow(BACKENDS_KEY)).toContain('enc:v1:');
const result = await service.testBackend({
name: 'cand-mirror',
type: 'mirror',
options: { primary: 'good-local', replicas: ['off-box'] },
});
expect(result.targets).toEqual([
{ name: 'good-local', ok: true },
expect.objectContaining({ name: 'off-box', ok: false }),
]);
// Decrypt succeeded: the replica failed on the network. A decrypt failure
// would reject the whole call (decryptBackendSecrets throws), not mark a target.
expect(result.targets[1]!.error).not.toContain('could not decrypt');
});
});
@@ -589,6 +589,33 @@ describe('seed-once storage-config.json import', () => {
expect(readRow('storage.backends')).toBe(firstRow);
expect(second.resolve('backups').backendName).toBe('nas');
});
it('SEED-010 an all-encrypted seed imports without ENCRYPTION_KEY (the gate is plaintext-only)', () => {
const cipher = encrypt_api_key('sk-seed');
writeSeed(
JSON.stringify({
backends: [
{
name: 'off-box',
type: 's3',
options: {
endpoint: 'http://127.0.0.1:9000',
bucket: 'trek',
accessKeyId: 'ak',
secretAccessKey: cipher,
},
},
],
categories: { backups: 'off-box' },
}),
);
const registry = makeUnseededRegistry({ encryptionKeySet: false });
registry.onModuleInit();
// enc:v1: values are not "plaintext secrets" — the key-presence gate must
// not fire, and the ciphertext must persist byte-for-byte (idempotent encrypt).
expect(registry.resolve('backups').driver).toBeInstanceOf(S3Driver);
expect(readRow('storage.backends')).toContain(cipher);
});
});
// ── snapshot() — effective world with provenance ──────────────────────────────