fix(backups): подтверждать настройки и последнюю проверку S3
This commit is contained in:
1 parent
8e01666e0e
commit
30bd479a6f
14 files changed
+208
-64
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import { backupSchedulePayload } from "./backup-settings"
|
||||
import { backupSchedulePayload, backupStoragePayload } from "./backup-settings"
|
||||
const form = { enabled: false, frequency: "daily" as const, hour: "0", minute: "7", weekDay: 0, monthDay: 1, keepCount: "365", format: "rsc" as const }
|
||||
test("schedule preserves zero, arbitrary minute and explicit all-enabled semantics", () => {
|
||||
const result = backupSchedulePayload(form, ["1"], true)
|
||||
@@ -16,3 +16,11 @@ test("unsupported binary schedule requires an explicit format choice", () => {
|
||||
assert.throws(() => backupSchedulePayload({ ...form, enabled: true, format: "backup" }, ["1"], false))
|
||||
assert.equal(backupSchedulePayload({ ...form, format: "backup" }, ["1"], false).format, "backup")
|
||||
})
|
||||
|
||||
const storageForm = { provider: "s3" as const, s3Endpoint: "", s3Region: "", s3Bucket: "bucket", s3Prefix: "", s3AccessKeyId: "key", s3SecretAccessKey: "", s3ForcePathStyle: false, keepLocalCopy: false, showPassword: false }
|
||||
test("S3 requires complete fields, endpoint protocol and a new or existing secret", () => {
|
||||
assert.throws(() => backupStoragePayload(storageForm))
|
||||
assert.equal(backupStoragePayload(storageForm, true).s3SecretAccessKey, undefined)
|
||||
assert.equal(backupStoragePayload({ ...storageForm, s3SecretAccessKey: "new-test-secret" }).s3SecretAccessKey, "new-test-secret")
|
||||
for (const patch of [{ s3Bucket: " " }, { s3AccessKeyId: " " }, { s3Endpoint: "invalid" }, { s3Endpoint: "ftp://example.test" }, { s3SecretAccessKey: " " }]) assert.throws(() => backupStoragePayload({ ...storageForm, ...patch }, true))
|
||||
})
|
||||
+11
-1
@@ -12,6 +12,16 @@ export function backupSchedulePayload(form: BackupScheduleForm, serverIds: strin
|
||||
if (form.enabled && form.format !== "rsc") throw new Error("Плановый binary backup пока не поддерживается; выберите .rsc явно")
|
||||
return putBackupScheduleSettingsSchema.parse({ ...form, hour: integer(form.hour, "Час", 0, 23), minute: integer(form.minute, "Минута", 0, 59), weekDay: integer(form.weekDay, "День недели", 0, 6), monthDay: integer(form.monthDay, "День месяца", 1, 28), keepCount: integer(form.keepCount, "Число копий", 1, 365), serverIds: allEnabled ? [] : serverIds })
|
||||
}
|
||||
export function backupStoragePayload(form: BackupStorageForm) {
|
||||
export function backupStoragePayload(form: BackupStorageForm, secretConfigured = false) {
|
||||
if (form.provider === "s3") {
|
||||
if (!form.s3Bucket.trim() || !form.s3AccessKeyId.trim()) throw new Error("Для S3 заполните Bucket и Access key")
|
||||
if (!form.s3SecretAccessKey.trim() && !secretConfigured) throw new Error("Для S3 требуется Secret key")
|
||||
if (form.s3SecretAccessKey && !form.s3SecretAccessKey.trim()) throw new Error("Secret key не может состоять только из пробелов")
|
||||
if (form.s3Endpoint) {
|
||||
let endpoint: URL
|
||||
try { endpoint = new URL(form.s3Endpoint) } catch { throw new Error("Endpoint должен быть полным URL http/https") }
|
||||
if (!["http:", "https:"].includes(endpoint.protocol)) throw new Error("Endpoint должен использовать http/https")
|
||||
}
|
||||
}
|
||||
return putBackupStorageSettingsSchema.parse({ provider: form.provider, s3Endpoint: form.s3Endpoint, s3Region: form.s3Region, s3Bucket: form.s3Bucket, s3Prefix: form.s3Prefix, s3AccessKeyId: form.s3AccessKeyId, s3SecretAccessKey: form.s3SecretAccessKey || undefined, s3ForcePathStyle: form.s3ForcePathStyle, keepLocalCopy: form.keepLocalCopy })
|
||||
}
|
||||
Reference in new issue
Block a user