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>
29 lines
1.1 KiB
TypeScript
29 lines
1.1 KiB
TypeScript
/**
|
|
* 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');
|
|
});
|
|
});
|