fix(docker-watcher): address final review findings

Security:
- Move config export behind auth middleware
- Validate OIDC callback token before storing in localStorage
- Use constant-time comparison for webhook secret
- Encrypt OIDC client secret at rest (like registry tokens)

Performance:
- Make TriggerDeploy async from HTTP handlers (return deploy ID
  immediately, run pipeline in background goroutine)

Robustness:
- Wrap api.ts res.json() in try/catch for non-JSON responses

i18n:
- Replace ~20 hardcoded English validation messages with $t() calls
- Localize ConfirmDialog cancel button, InstanceCard confirm titles,
  ProjectCard instance/instances pluralization
- Add validation keys to both en.json and ru.json
This commit is contained in:
2026-03-28 00:14:53 +03:00
parent a3aa5912d9
commit 1f81ca9eb0
17 changed files with 178 additions and 40 deletions
+21 -1
View File
@@ -316,7 +316,9 @@
"stop": "Stop",
"start": "Start",
"restart": "Restart",
"remove": "Remove"
"remove": "Remove",
"instance": "instance",
"instances": "instances"
},
"instance": {
"stopConfirm": "This will stop the running container. The instance can be started again later.",
@@ -339,6 +341,24 @@
"noUsers": "No users",
"noUsersDesc": "Add local users to manage access."
},
"validation": {
"required": "{field} is required",
"invalidUrl": "Invalid URL format",
"invalidDomain": "Invalid domain format",
"invalidIp": "Invalid IP format",
"invalidEmail": "Invalid email format",
"invalidPort": "Port must be between 1 and 65535",
"invalidPollingInterval": "Polling interval must be between 10 and 86400 seconds",
"invalidProjectName": "Only lowercase letters, numbers, and hyphens allowed",
"requiredWhenUpdating": "{field} is required when updating credentials",
"requiredForNew": "{field} is required for new registries"
},
"confirm": {
"stopInstance": "Stop Instance",
"startInstance": "Start Instance",
"restartInstance": "Restart Instance",
"removeInstance": "Remove Instance"
},
"theme": {
"light": "Light",
"dark": "Dark",
+21 -1
View File
@@ -316,7 +316,9 @@
"stop": "Остановить",
"start": "Запустить",
"restart": "Перезапустить",
"remove": "Удалить"
"remove": "Удалить",
"instance": "экземпляр",
"instances": "экземпляров"
},
"instance": {
"stopConfirm": "Контейнер будет остановлен. Экземпляр можно будет запустить снова позже.",
@@ -339,6 +341,24 @@
"noUsers": "Нет пользователей",
"noUsersDesc": "Добавьте локальных пользователей для управления доступом."
},
"validation": {
"required": "Поле {field} обязательно",
"invalidUrl": "Неверный формат URL",
"invalidDomain": "Неверный формат домена",
"invalidIp": "Неверный формат IP",
"invalidEmail": "Неверный формат email",
"invalidPort": "Порт должен быть от 1 до 65535",
"invalidPollingInterval": "Интервал опроса должен быть от 10 до 86400 секунд",
"invalidProjectName": "Допускаются только строчные буквы, цифры и дефисы",
"requiredWhenUpdating": "Поле {field} обязательно при обновлении учётных данных",
"requiredForNew": "Поле {field} обязательно для новых реестров"
},
"confirm": {
"stopInstance": "Остановить экземпляр",
"startInstance": "Запустить экземпляр",
"restartInstance": "Перезапустить экземпляр",
"removeInstance": "Удалить экземпляр"
},
"theme": {
"light": "Светлая",
"dark": "Тёмная",