Repository navigation
feat: check read, write and delete access in destination test - #20
Merged
Merged
Conversation
Что:
- Кнопка Test у S3-назначения теперь по очереди проверяет чтение (rclone ls корня бакета, те же retry/timeout флаги), запись (rclone rcat маленького объекта dokploy-connection-test/<время>-<случайный>.txt) и удаление этого объекта (rclone deletefile). Удаление пропускается, если запись не удалась. Команды идут туда же, что и раньше: execAsync локально или execAsyncRemote в cloud.
- При успехе testConnection возвращает { read, write, delete } с ok: true. Если хоть одна проверка не прошла, бросается BAD_REQUEST с построчным отчётом, например "Read: OK / Write: FAILED - 403 AccessDenied (the key cannot upload objects) / Delete: SKIPPED". Если объект записан, но не удалён, в отчёте указан его путь.
- Причина ошибки rclone сокращается до HTTP-статуса и кода S3, проходит через redactSensitiveText и замену значений ключей; командная строка в причину не попадает.
- Диалог назначения показывает список проверок (✓/✗/пропуск и причина) рядом с кнопкой Test; тост стал коротким и отсылает к списку.
- Новые тесты destination-connection-test.test.ts и destination-connection-report.test.ts; обновлены destination-router-assigned-server.test.ts и rclone-command-boundary.test.ts под новый результат и три команды.
Зачем:
- Ключ с правом только на чтение проходил старую проверку (только rclone ls), а ночные бэкапы падали с PutObject 403. Теперь Test показывает, какого именно доступа не хватает.
Риски:
- Проверка записи создаёт и удаляет настоящий объект в бакете под префиксом dokploy-connection-test/. Если удаление запрещено, объект остаётся, путь указан в отчёте.
- Вместо одного вызова rclone теперь до трёх, поэтому при недоступном endpoint проверка идёт дольше.
- Успешный ответ testConnection теперь объект, а не пустое значение.
- Диалог разбирает текст ошибки по формату "Read|Write|Delete: OK|FAILED|SKIPPED"; формат и разбор лежат в одном модуле connection-test-report.ts.
Проверки:
- Команды и результаты: из apps/dokploy `CI=true bunx vitest run --config __test__/vitest.config.ts __test__/destination/destination-connection-test.test.ts __test__/destination/destination-connection-report.test.ts` - 12 passed; на старом router все 7 новых router-тестов падают по assertion, report-тест падает без нового модуля; `... __test__/destination` - 4 files, 30 passed; `... __test__/backup/rclone-command-boundary.test.ts` - 6 passed; полный набор - 234 files passed, падают только *.real.test.ts (нет Docker socket) и два файла по таймауту под нагрузкой (better-auth-schema-compat, cloud-queue-availability), которые проходят отдельно. Из корня `bun run typecheck` - exit 0; `bun run format-and-lint` - 0 errors (33 warnings и 16 infos уже были, в изменённых файлах нет).
- Ограничения: не проверялось на настоящем S3 endpoint; диалог не открывался в браузере, проверен только typecheck и lint; разбор причин ошибок rclone проверен на примерах вывода, а не на всех провайдерах.
What:
- The S3 destination Test button now runs three checks in order: read (rclone ls of the bucket root with the same retry/timeout flags), write (rclone rcat of a tiny object at dokploy-connection-test/<timestamp>-<random>.txt) and delete of that object (rclone deletefile). Delete is skipped when the write fails. Commands run on the same target as before: execAsync locally or execAsyncRemote in cloud mode.
- On success testConnection returns { read, write, delete } with ok: true. If any check fails it throws BAD_REQUEST with a line per check, for example "Read: OK / Write: FAILED - 403 AccessDenied (the key cannot upload objects) / Delete: SKIPPED". When the object was written but not deleted, the report names its path.
- An rclone failure is reduced to the HTTP status and S3 error code, passed through redactSensitiveText and key-value replacement; the command line never reaches the reason.
- The destination dialog shows the per-check list (check/cross/skipped with the reason) next to the Test button; the toast is short and points to the list.
- New tests destination-connection-test.test.ts and destination-connection-report.test.ts; destination-router-assigned-server.test.ts and rclone-command-boundary.test.ts updated for the new result and the three commands.
Why:
- A read-only key passed the old check (rclone ls only) while nightly backups failed with PutObject 403. Test now shows exactly which access is missing.
Risks:
- The write check creates and deletes a real object in the bucket under dokploy-connection-test/. If delete is forbidden the object stays and its path is in the report.
- Up to three rclone calls instead of one, so the test takes longer when the endpoint is unreachable.
- A successful testConnection response is now an object instead of an empty value.
- The dialog parses the error text in the "Read|Write|Delete: OK|FAILED|SKIPPED" format; formatting and parsing live in the same connection-test-report.ts module.
Checks:
- Commands and results: from apps/dokploy `CI=true bunx vitest run --config __test__/vitest.config.ts __test__/destination/destination-connection-test.test.ts __test__/destination/destination-connection-report.test.ts` - 12 passed; against the old router all 7 new router tests fail on assertions and the report test fails without the new module; `... __test__/destination` - 4 files, 30 passed; `... __test__/backup/rclone-command-boundary.test.ts` - 6 passed; full suite - 234 files passed, only *.real.test.ts (no Docker socket) and two files timing out under load (better-auth-schema-compat, cloud-queue-availability) fail, and both pass on their own. From the root `bun run typecheck` - exit 0; `bun run format-and-lint` - 0 errors (33 warnings and 16 infos already existed, none in changed files).
- Limitations: not run against a real S3 endpoint; the dialog was not opened in a browser, only typecheck and lint cover it; rclone error parsing is checked on sample output, not on every provider.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is this PR about?
The S3 destination Test button only ran
rclone ls, so a key that can read but not write passed the test, and scheduled backups later failed withPutObject ... StatusCode: 403. This PR makes the test check read, write and delete access separately and show which ones work.Server (
destination.testConnection)execAsynclocally,execAsyncRemotein cloud mode):rclone lsof the bucket root, same retry/timeout flags as before;rclone rcatof a tiny object atdokploy-connection-test/<timestamp>-<random>.txt(content is piped in withprintf; every argument goes throughshell-quote);rclone deletefileof that same object. Skipped when the write failed.{ read: { ok: true }, write: { ok: true }, delete: { ok: true } }.BAD_REQUESTwith one line per check, so API/MCP clients still get an error:<bucket>/dokploy-connection-test/....txt).redactSensitiveText, and the access key and secret values are replaced. The command line (which carries the credentials as env assignments) never reaches the reason.packages/server/src/utils/destination/connection-test.ts(commands, runner, failure summary) andconnection-test-report.ts(client-safe types plus format/parse of the report lines).UI (
handle-destinations.tsx)For a read-only key, the dialog now shows:
Checks
From
apps/dokploy:CI=true bunx vitest run --config __test__/vitest.config.ts __test__/destination/destination-connection-test.test.ts __test__/destination/destination-connection-report.test.ts: 12 passed.CI=true bunx vitest run --config __test__/vitest.config.ts __test__/destination: 4 files, 30 passed.CI=true bunx vitest run --config __test__/vitest.config.ts __test__/backup/rclone-command-boundary.test.ts: 6 passed. It now checks that all three commands pass credentials only as env and quote hostile bucket names.*.real.test.tsfiles (no Docker socket locally) and two files that time out under full-suite load (better-auth-schema-compat,cloud-queue-availability). Both pass when run on their own and are unrelated to this change.From the repo root:
bun run typecheck: exit 0.bun run format-and-lint: 0 errors. The 33 warnings and 16 infos were already there, and none are in the changed files.The new tests cover:
/bin/shwith a stubrcloneand a hostile bucket name. Nothing gets injected, and the target is underdokploy-connection-test/.Not checked: a real S3 endpoint. The dialog was not opened in a browser, so only typecheck and lint cover it.
Rollout notes
dokploy-connection-test/in the bucket. If the key cannot delete, that object stays and the dialog names it so it can be removed by hand.destination.testConnectionnow returns an object on success instead of an empty value. Callers that ignore the result are unaffected.🤖 Generated with Claude Code