fix(storage): make S3 server-side-encryption optional (default off)
Prod MinIO has no KMS/KES, so the unconditional
`x-amz-server-side-encryption: AES256` header on every PutObject was
rejected with `NotImplemented` ("KMS not configured") — breaking ALL
server-side uploads on prod: avatars, the signed-PDF deposit on
Documenso completion, GDPR exports, the nightly DB backup, generated
EOI/contract PDFs, report renders. Reads/presigned downloads were
unaffected, so the cutover walkthrough missed it.
The SSE header is now sent only when explicitly configured via the
per-port `storage_s3_sse` setting (or the STORAGE_S3_SSE env fallback);
the default is off so a vanilla S3-compatible backend accepts uploads.
This also resolves the put()-encrypts-but-presignUpload-doesn't
asymmetry — presigned PUTs never sent SSE, so both paths now match by
default.
Extracted buildPutObjectMetadata() as a pure, unit-tested helper.
Interim fix; the planned filesystem-storage migration removes SSE from
the prod path entirely.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
28
tests/unit/storage/s3-sse.test.ts
Normal file
28
tests/unit/storage/s3-sse.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* SSE (server-side-encryption) header policy for the S3 backend.
|
||||
*
|
||||
* Regression (2026-06-03 prod): MinIO with no KMS/KES rejected EVERY
|
||||
* PutObject because `put()` unconditionally sent
|
||||
* `x-amz-server-side-encryption: AES256`, which a backend without KMS
|
||||
* answers with `NotImplemented` ("KMS not configured"). The header must
|
||||
* only be sent when SSE is explicitly configured; the default is OFF so
|
||||
* a vanilla S3-compatible backend accepts uploads.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { buildPutObjectMetadata } from '@/lib/storage/s3';
|
||||
|
||||
describe('buildPutObjectMetadata', () => {
|
||||
it('omits the server-side-encryption header when no SSE is configured', () => {
|
||||
const meta = buildPutObjectMetadata('application/pdf', undefined);
|
||||
expect(meta['Content-Type']).toBe('application/pdf');
|
||||
expect(meta['x-amz-server-side-encryption']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('sends the configured SSE algorithm when one is set', () => {
|
||||
const meta = buildPutObjectMetadata('image/png', 'AES256');
|
||||
expect(meta['Content-Type']).toBe('image/png');
|
||||
expect(meta['x-amz-server-side-encryption']).toBe('AES256');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user