@@ -87,7 +87,7 @@ export default function HowToAddStoragePage() {
8787 build the frontend UI components for managing storage providers.
8888 </ p >
8989
90- < div className = "rounded-lg border border-blue-200 bg-blue-50 p -4 my-6" >
90+ < div className = "rounded-lg border border-blue-200 bg-blue-50 pt-4 px -4 my-6" >
9191 < p className = "text-sm text-blue-900 m-0" >
9292 < strong > 💡 Note:</ strong > This is a contribution guide for
9393 developers who want to add new storage integrations to the
@@ -124,34 +124,63 @@ export default function HowToAddStoragePage() {
124124 < ul >
125125 < li >
126126 < code >
127- SaveFile(logger *slog.Logger, fileID uuid.UUID, file
128- io.Reader) error
127+ SaveFile(encryptor encryption.FieldEncryptor, logger
128+ *slog.Logger, fileID uuid.UUID, file io.Reader) error
129129 </ code > { " " }
130130 - saves a backup file to the storage
131131 </ li >
132132 < li >
133- < code > GetFile(fileID uuid.UUID) (io.ReadCloser, error)</ code > { " " }
133+ < code >
134+ GetFile(encryptor encryption.FieldEncryptor, fileID
135+ uuid.UUID) (io.ReadCloser, error)
136+ </ code > { " " }
134137 - retrieves a backup file from the storage
135138 </ li >
136139 < li >
137- < code > DeleteFile(fileID uuid.UUID) error</ code > - deletes a
138- backup file from the storage
140+ < code >
141+ DeleteFile(encryptor encryption.FieldEncryptor, fileID
142+ uuid.UUID) error
143+ </ code > { " " }
144+ - deletes a backup file from the storage
139145 </ li >
140146 < li >
141- < code > Validate() error</ code > - validates the storage
142- configuration
147+ < code >
148+ Validate(encryptor encryption.FieldEncryptor) error
149+ </ code > { " " }
150+ - validates the storage configuration
143151 </ li >
144152 < li >
145- < code > TestConnection() error</ code > - tests connectivity to
146- the storage provider
153+ < code >
154+ TestConnection(encryptor encryption.FieldEncryptor) error
155+ </ code > { " " }
156+ - tests connectivity to the storage provider
147157 </ li >
148158 < li >
149159 < code > HideSensitiveData()</ code > - masks sensitive fields like
150160 API keys before logging/display
151161 </ li >
162+ < li >
163+ < code >
164+ EncryptSensitiveData(encryptor encryption.FieldEncryptor)
165+ error
166+ </ code > { " " }
167+ - encrypts sensitive fields before saving
168+ </ li >
152169 </ ul >
153170
154- < div className = "rounded-lg border border-gray-200 bg-gray-50 p-4 my-6" >
171+ < div className = "rounded-lg border border-blue-200 bg-blue-50 pt-4 px-4 my-6" >
172+ < p className = "text-sm text-blue-900 m-0" >
173+ < strong > 🔐 Encryption requirement:</ strong > All sensitive
174+ fields (API keys, passwords, access tokens, secrets) must be
175+ encrypted using the < code > EncryptSensitiveData()</ code > method
176+ before saving to the database. Decrypt credentials before
177+ using them. See < code > azure_blob</ code > ,{ " " }
178+ < code > google_drive</ code > or < code > s3</ code > storage models
179+ for implementation examples.
180+ </ p >
181+ </ div >
182+
183+ < div className = "rounded-lg border border-gray-200 bg-gray-50 pt-4 px-4 my-6" >
155184 < p className = "text-sm text-gray-700 m-0" >
156185 < strong > 🔑 Important:</ strong > Use UUID primary key as{ " " }
157186 < code > StorageID</ code > that references the main storages
@@ -258,7 +287,7 @@ export default function HowToAddStoragePage() {
258287 </ li >
259288 </ ul >
260289
261- < div className = "rounded-lg border border-gray-200 bg-gray-50 p -4 my-6" >
290+ < div className = "rounded-lg border border-gray-200 bg-gray-50 pt-4 px -4 my-6" >
262291 < p className = "text-sm text-gray-700 m-0" >
263292 < strong > 💡 Tip:</ strong > The < code > CASCADE DELETE</ code > { " " }
264293 ensures that when a storage is deleted from the main storages
@@ -282,6 +311,39 @@ export default function HowToAddStoragePage() {
282311 < li > Validation of configuration parameters</ li >
283312 </ ul >
284313
314+ < p >
315+ Additionally, update{ " " }
316+ < code >
317+ backend/internal/features/storages/controller_test.go
318+ </ code > { " " }
319+ to add encryption verification tests:
320+ </ p >
321+
322+ < ul >
323+ < li >
324+ Add a test case to{ " " }
325+ < code > Test_StorageSensitiveDataLifecycle_AllTypes</ code > for
326+ your storage type
327+ </ li >
328+ < li >
329+ Add a test case to{ " " }
330+ < code >
331+ Test_CreateStorage_AllSensitiveFieldsEncryptedInDB
332+ </ code > { " " }
333+ (if not already present)
334+ </ li >
335+ < li >
336+ Verify that sensitive fields are encrypted with{ " " }
337+ < code > enc:</ code > prefix in the database
338+ </ li >
339+ < li >
340+ Verify that decryption returns the original plaintext values
341+ </ li >
342+ < li >
343+ Verify that sensitive data is hidden when retrieved via API
344+ </ li >
345+ </ ul >
346+
285347 < h3 id = "step-9-run-tests" > 9. Run all tests</ h3 >
286348
287349 < p >
@@ -299,7 +361,7 @@ export default function HowToAddStoragePage() {
299361 provider.
300362 </ p >
301363
302- < div className = "rounded-lg border border-amber-200 bg-amber-50 p -4 my-6" >
364+ < div className = "rounded-lg border border-amber-200 bg-amber-50 pt-4 px -4 my-6" >
303365 < p className = "text-sm text-amber-900 m-0" >
304366 < strong > ℹ️ Backend-only contributions:</ strong > If you're
305367 only comfortable with backend development, that's
@@ -466,7 +528,7 @@ export default function HowToAddStoragePage() {
466528 </ li >
467529 </ ol >
468530
469- < div className = "rounded-lg border border-green-200 bg-green-50 p -4 my-6" >
531+ < div className = "rounded-lg border border-green-200 bg-green-50 pt-4 px -4 my-6" >
470532 < p className = "text-sm text-green-900 m-0" >
471533 < strong > 🎉 Thank you!</ strong > Your contributions help make
472534 Postgresus more versatile and valuable for the community. We
0 commit comments