Skip to content

fix: repair s3 backup connection test, file listing and failure logs - #6

Merged
agentHits merged 4 commits into
AgentHits-Devfrom
fix/s3-backups
Oct 6, 2026
Merged

agentHits merged 4 commits into
AgentHits-Devfrom
fix/s3-backups

Conversation

@agentHits

Copy link
Copy Markdown
Collaborator

What is this PR about?

Fixes three S3 backup problems found while setting up an S3 backup destination on dev, one commit each, plus a small log fix:

  • Destination Test always failed with 403 SignatureDoesNotMatch (193263a). The API returns secretAccessKey to the edit form as the __DOKPLOY_REDACTED_SECRET__ placeholder, the form sent it back, and rclone signed the request with the placeholder. destination.testConnection now accepts an optional destinationId. When the placeholder arrives, it uses that destination's stored secret after the same organization check as one and update; cloud server access is still checked first. The placeholder without destinationId is rejected with a clear BAD_REQUEST before rclone runs. The edit form sends destinationId.
  • backup.listBackupFiles always answered 400 (2802c33). The application table has 101 columns. The volumeBackups listing query loaded application: true, and Drizzle packed every column into one json_build_array(...), above the Postgres limit of 100 arguments (54023 cannot pass more than 100 arguments to a function). The nested application and compose relations now select only appName.
  • Backup logs lost the failure reason, and every backup dumped and uploaded twice (5bc9363). An upstream merge left a second dump-and-upload block in getBackupCommand and dropped the partial-upload cleanup. The script now dumps once. On failure it deletes the partial object (as upstream does) and prints UPLOAD_OUTPUT to stderr instead of the log. The new runBackupCommand passes that output through redactSensitiveText and appends it to the deployment log, locally or over SSH. All six database runners use it.
  • Log cosmetics (6b90c3b): redactSensitiveText no longer masks the database name after pg_dump --no-password. Real password arguments stay masked.

No database migrations and no new environment variables; only the dokploy service image changes.

Checks

  • The new regression tests fail on the old code and pass now: destination router (4 of the 6 new tests fail before the fix), listing SQL compiled with drizzle.mock and the real schema (old code: 101 arguments), the backup script run in bash with fake docker and rclone (old code: dump and upload twice, no cleanup), runBackupCommand log appends, redaction.
  • Vitest in __test__/destination, __test__/backup, __test__/backups and __test__/security: 22 files, 182 tests pass.
  • bun run typecheck: 4/4 packages pass.
  • bun run format-and-lint: no errors.
  • bun run test: 2064 pass; the 8 failures are only in *.real.test.ts (no local Docker daemon, real build timeouts).
  • Not run: the Test button against the real S3 endpoint and a real backup to S3; nothing is deployed yet.

Rollout notes

  • Before rollout, record the running dokploy image and take a database backup.
  • After rollout: Test on the saved destination passes without retyping the secret; the Restore dialog lists backup files; a manual Postgres backup shows a single upload block, and a failed one shows the masked reason in its log.

Not in this PR

findDeploymentById and the volume-backup restore check still load application: true and hit the same 54023 error (deployment log viewer, readLogs, kill and remove deployment, rollbacks, volume restore). They are being fixed in a separate branch.

🤖 Generated with Claude Code

agentHits and others added 4 commits October 6, 2026 13:54
Что:
- destination.testConnection принимает необязательный destinationId. Если форма прислала заглушку __DOKPLOY_REDACTED_SECRET__, роутер берёт сохранённый секрет этого destination после той же проверки organizationId, что в one и update. В облаке доступ к серверу проверяется до загрузки секрета.
- Заглушка без destinationId отклоняется ошибкой BAD_REQUEST с понятным текстом до запуска rclone.
- Форма редактирования destination передаёт destinationId при нажатии Test.
Зачем:
- API отдаёт форме секрет в виде заглушки, форма отправляла её обратно, и rclone подписывал запрос заглушкой. Поэтому Test для сохранённого S3 destination всегда падал с 403 SignatureDoesNotMatch.
Риски:
- Секрет, введённый в форме заново, используется как раньше; сохранённый подставляется только вместо заглушки. Значимых рисков не выявлено.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/destination __test__/backup __test__/backups __test__/security - 22 файла, 182 теста прошли; 4 из 6 новых тестов падают на старом роутере. bun run typecheck - 4 из 4 workspace без ошибок. bun run format-and-lint - exit 0, только прежние предупреждения в чужих файлах. CI=true bun run test - 2064 прошли, 8 упали только в *.real.test.ts (нет локального Docker daemon, таймауты реальной сборки).
- Ограничения: проверки запускались на дереве со всеми исправлениями этой серии; кнопка Test не нажималась в браузере против реального S3; ничего не выкатывалось.

What:
- destination.testConnection accepts an optional destinationId. When the form sends the __DOKPLOY_REDACTED_SECRET__ placeholder, the router uses the stored secret of that destination after the same organizationId check as one and update. In cloud mode server access is checked before the secret is loaded.
- The placeholder without destinationId is rejected with a clear BAD_REQUEST before rclone runs.
- The destination edit form sends destinationId when Test is pressed.
Why:
- The API returns the secret to the form as a placeholder, the form sent it back, and rclone signed the request with the placeholder. Test on a saved S3 destination therefore always failed with 403 SignatureDoesNotMatch.
Risks:
- A secret typed again in the form is used as before; the stored one only replaces the placeholder. No significant risks identified.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/destination __test__/backup __test__/backups __test__/security - 22 files, 182 tests passed; 4 of the 6 new tests fail on the old router. bun run typecheck - 4 of 4 workspaces clean. bun run format-and-lint - exit 0, only existing warnings in unrelated files. CI=true bun run test - 2064 passed, 8 failed only in *.real.test.ts (no local Docker daemon, real build timeouts).
- Limitations: checks ran on the tree with every fix of this series; the Test button was not pressed in a browser against a real S3 endpoint; nothing was deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Что:
- getAccessibleBackupListingPrefixes загружает из связей application и compose запроса volumeBackups только appName.
- Тест собирает настоящий SQL обоих запросов listBackupFiles через drizzle.mock с реальной схемой и проверяет, что ни один json_build_array не получает больше 100 аргументов.
Зачем:
- В таблице application 101 колонка. Drizzle упаковывает все колонки вложенной связи в один json_build_array, и Postgres отклонял запрос с 54023 "cannot pass more than 100 arguments to a function". Из-за этого backup.listBackupFiles всегда отвечал 400 и восстановление из бэкапа нельзя было начать.
Риски:
- Запрос backups (связи compose, postgres и другие) не менялся: сейчас максимум 49 аргументов, и тест упадёт, если он перейдёт порог. Тот же класс ошибки остаётся в других запросах с application: true (findDeploymentById, проверка восстановления volume backup) - они вне этой правки.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/backup/restore-security.test.ts - 40 тестов прошли; на старом роутере новый тест падает с "expected 101 to be less than or equal to 100". Общие прогоны те же, что в предыдущем коммите серии: 182 теста в затронутых областях прошли, bun run typecheck 4/4 без ошибок, bun run format-and-lint exit 0.
- Ограничения: проверки запускались на дереве со всеми исправлениями этой серии; запрос не выполнялся против живой базы; ничего не выкатывалось.

What:
- getAccessibleBackupListingPrefixes loads only appName from the application and compose relations of the volumeBackups query.
- A test compiles the real SQL of both listBackupFiles queries with drizzle.mock and the real schema and checks that no json_build_array call gets more than 100 arguments.
Why:
- The application table has 101 columns. Drizzle packs every column of a nested relation into one json_build_array call, and Postgres rejected the query with 54023 "cannot pass more than 100 arguments to a function". backup.listBackupFiles therefore always answered 400 and a restore could not be started.
Risks:
- The backups query (compose, postgres and other relations) is unchanged: it peaks at 49 arguments now, and the test fails if it crosses the limit. The same error class remains in other application: true queries (findDeploymentById, the volume backup restore check), which are outside this fix.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/backup/restore-security.test.ts - 40 tests passed; on the old router the new test fails with "expected 101 to be less than or equal to 100". Shared runs are the same as in the previous commit of the series: 182 tests passed in the touched areas, bun run typecheck 4/4 clean, bun run format-and-lint exit 0.
- Limitations: checks ran on the tree with every fix of this series; the query was not run against a live database; nothing was deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Что:
- Скрипт getBackupCommand делает дамп и выгрузку один раз: удалён второй блок "Starting upload to S3...", который заново запускал дамп и rclone rcat.
- При ошибке скрипт пишет в лог "Backup failed", удаляет недокачанный файл через уже передаваемый rcloneDeleteCommand (как в upstream) и печатает UPLOAD_OUTPUT в stderr, а не в лог.
- Новый runBackupCommand в backups/utils запускает скрипт локально или на удалённом сервере, при ошибке пропускает stderr через redactSensitiveText и дописывает его в logPath деплоя (локально через appendFile, удалённо через printf с экранированием). Шесть раннеров (postgres, mysql, mariadb, mongo, libsql, compose) вызывают его вместо своей копии if/else.
Зачем:
- Причина ошибки pg_dump или rclone сохранялась в UPLOAD_OUTPUT и терялась: в логе бэкапа было только "Check server logs for details", в логах сервера деталей тоже не было. Дамп и выгрузка шли дважды, удваивая нагрузку и время. Повторный блок и потеря очистки появились при слиянии upstream f633d4b.
Риски:
- Удалённый лог дописывается вторым SSH-вызовом; если он не удался, ошибка пишется в лог сервера, а исходная ошибка бэкапа пробрасывается без изменений. Маскировка покрывает только шаблоны redactSensitiveText.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/backup/backup-failure-output.test.ts __test__/backup/rclone-command-boundary.test.ts - все прошли. Новый тест запускает настоящий скрипт в bash с поддельными docker и rclone; на старом utils.ts он показывает второй docker exec и rclone rcat и отсутствие deletefile. Общие прогоны серии: 182 теста в затронутых областях прошли, bun run typecheck 4/4 без ошибок, bun run format-and-lint exit 0.
- Ограничения: проверки запускались на дереве со всеми исправлениями этой серии; настоящий бэкап в S3 не запускался; ничего не выкатывалось.

What:
- The getBackupCommand script dumps and uploads once: the second "Starting upload to S3..." block that re-ran the dump and rclone rcat is removed.
- On failure the script logs "Backup failed", removes the partial upload with the already passed rcloneDeleteCommand (as upstream does) and prints UPLOAD_OUTPUT to stderr instead of the log.
- A new runBackupCommand in backups/utils runs the script locally or on a remote server and, on failure, passes stderr through redactSensitiveText and appends it to the deployment logPath (appendFile locally, quoted printf remotely). The six runners (postgres, mysql, mariadb, mongo, libsql, compose) call it instead of their own if/else copy.
Why:
- The pg_dump or rclone failure reason was captured in UPLOAD_OUTPUT and lost: the backup log only said "Check server logs for details", and the server logs had no details either. The dump and upload ran twice, doubling load and time. The duplicate block and the lost cleanup came from merging upstream f633d4b.
Risks:
- The remote log is appended with a second SSH call; if it fails, the error goes to the server log and the original backup error is rethrown unchanged. Masking covers only the redactSensitiveText patterns.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/backup/backup-failure-output.test.ts __test__/backup/rclone-command-boundary.test.ts - all passed. The new test runs the real script in bash with fake docker and rclone; against the old utils.ts it shows a second docker exec and rclone rcat and no deletefile. Shared runs of the series: 182 tests passed in the touched areas, bun run typecheck 4/4 clean, bun run format-and-lint exit 0.
- Limitations: checks ran on the tree with every fix of this series; no real backup to S3 was run; nothing was deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Что:
- redactSensitiveText больше не маскирует слово после флагов вида --no-password: правило для флагов CLI пропускает флаги --no-*, а правило PASSWORD не срабатывает на no-password.
- Тест проверяет, что имя БД после --no-password остаётся видимым, а --password, --db-password=, -password, PASSWORD '...' и IDENTIFIED BY '...' по-прежнему маскируются.
Зачем:
- В логе команды бэкапа postgres имя базы после --no-password заменялось на заглушку, хотя это не секрет: флаг булев и значения не принимает.
Риски:
- Правка общей функции маскировки. Исключение узкое: только флаги, начинающиеся с no-, которые по соглашению не принимают значений. Прочие правила не менялись.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/security/secret-redaction.test.ts - 14 тестов прошли; на старом redaction.ts новый тест падает. Общие прогоны серии: 182 теста в затронутых областях прошли, bun run typecheck 4/4 без ошибок, bun run format-and-lint exit 0, CI=true bun run test - 2064 прошли, 8 упали только в *.real.test.ts (нет локального Docker daemon, таймауты реальной сборки).
- Ограничения: проверки запускались на дереве со всеми исправлениями этой серии; ничего не выкатывалось.

What:
- redactSensitiveText no longer masks the word after flags such as --no-password: the CLI flag rule skips --no-* flags, and the PASSWORD rule does not match no-password.
- A test checks that the database name after --no-password stays visible while --password, --db-password=, -password, PASSWORD '...' and IDENTIFIED BY '...' are still masked.
Why:
- The postgres backup command log replaced the database name after --no-password with the placeholder, although it is not a secret: the flag is boolean and takes no value.
Risks:
- This changes the shared masking function. The exception is narrow: only flags starting with no-, which by convention take no value. Other rules are unchanged.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/security/secret-redaction.test.ts - 14 tests passed; the new test fails on the old redaction.ts. Shared runs of the series: 182 tests passed in the touched areas, bun run typecheck 4/4 clean, bun run format-and-lint exit 0, CI=true bun run test - 2064 passed, 8 failed only in *.real.test.ts (no local Docker daemon, real build timeouts).
- Limitations: checks ran on the tree with every fix of this series; nothing was deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agentHits added a commit that referenced this pull request Oct 6, 2026
Что:
- findDeploymentById берёт из трёх вложенных связей application (у самого деплоя, у schedule и у volumeBackup) только serverId: другие поля этих связей вызывающий код не читает.
- Проверка восстановления volume backup (assertVolumeRestoreObjectBound) берёт из связей application и compose только appName.
- Поиск preview-деплоя в monitoring-access берёт из связи application только applicationId и serverId.
- Новый тестовый хелпер __test__/helpers/postgres-function-args.ts собирает настоящий SQL через drizzle.mock с реальной схемой и считает аргументы json_build_array. Для каждого из трёх запросов добавлен тест, который проверяет, что аргументов не больше 100.
Зачем:
- В таблице application 101 колонка. Drizzle кладёт все выбранные колонки вложенной связи в один вызов json_build_array, а Postgres принимает не больше 100 аргументов и отвечает ошибкой 54023 "cannot pass more than 100 arguments to a function".
- Из-за findDeploymentById не работали WebSocket логов деплоя (закрывался молча), deployment.readLogs, killProcess и removeDeployment, откат через rollback и создание rollback при деплое с rollback registry. Удаление старых rollback молча пропускалось.
- Из-за проверки восстановления не запускалось восстановление volume backup.
- Поиск preview-деплоя выполняется для каждого имени, которое не нашлось среди application. Поэтому мониторинг compose, баз данных и preview-деплоев (WebSocket docker stats, user.getContainerMetrics) отвечал ошибкой.
- Upstream уже сужал связи в findDeploymentById (97885ee), но при слиянии upstream 430c888 конфликт разрешился в пользу application: true.
Риски:
- Если код начнёт читать из этих связей другие поля, их там не будет. Typecheck это ловит: при выборе appName вместо serverId tsc падает в listen-deployment.ts.
- backup.listBackupFiles в AgentHits-Dev падает с той же ошибкой. Его чинит открытый PR #6 (2802c33), здесь он не менялся. В тесте PR #6 своя копия подсчёта аргументов, после слияния её можно заменить общим хелпером.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/deployment/find-deployment-by-id.test.ts __test__/volume-backups/restore-security.test.ts __test__/server/container-resource-stats-access.test.ts - 28 тестов прошли; на старом коде три новых теста падают с "expected 101 to be less than or equal to 100" (для monitoring - 102). Полный прогон CI=true bunx vitest run --config __test__/vitest.config.ts: 2055 тестов прошли, 1 пропущен, 8 упали только в __test__/deploy/application.real.test.ts и __test__/setup/monitoring-setup.real.test.ts из-за отсутствия сокета Docker Desktop (connect ECONNREFUSED /Users/agent/.docker/run/docker.sock). bun run typecheck - 4/4 пакета без ошибок. bun run format-and-lint - 0 ошибок (33 предупреждения в других файлах, в изменённых файлах их нет). Временный vitest-аудит через toSQL (удалён перед коммитом) проверил остальные вложенные связи с application из grep: у них не больше 50 аргументов.
- Ограничения: запросы не выполнялись против живой базы; *.real.test.ts без локального Docker не проверены; ничего не пушилось и не выкатывалось.

What:
- findDeploymentById loads only serverId from its three nested application relations (on the deployment itself, on schedule and on volumeBackup); callers read no other field from them.
- The volume backup restore check (assertVolumeRestoreObjectBound) loads only appName from the application and compose relations.
- The preview deployment lookup in monitoring-access loads only applicationId and serverId from the application relation.
- A new test helper, __test__/helpers/postgres-function-args.ts, compiles the real SQL with drizzle.mock and the real schema and counts json_build_array arguments. Each of the three queries gets a test that checks there are no more than 100.
Why:
- The application table has 101 columns. Drizzle puts every selected column of a nested relation into one json_build_array call, and Postgres accepts at most 100 arguments and fails with 54023 "cannot pass more than 100 arguments to a function".
- Because of findDeploymentById, the deployment log WebSocket (closed silently), deployment.readLogs, killProcess and removeDeployment, rolling back, and rollback creation during deploys with a rollback registry all failed. Removing old rollbacks was silently skipped.
- Because of the restore check, a volume backup restore could not start.
- The preview deployment lookup runs for every name that is not found among applications. Monitoring for compose services, databases and preview deployments (the docker stats WebSocket, user.getContainerMetrics) therefore failed.
- Upstream had already narrowed the relations in findDeploymentById (97885ee), but the upstream merge 430c888 resolved the conflict in favour of application: true.
Risks:
- Code that starts reading other fields from these relations will not find them there. Typecheck catches this: selecting appName instead of serverId makes tsc fail in listen-deployment.ts.
- backup.listBackupFiles fails with the same error in AgentHits-Dev. Open PR #6 (2802c33) fixes it, so it is unchanged here. The PR #6 test has its own copy of the argument counter, which can switch to the shared helper after both are merged.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/deployment/find-deployment-by-id.test.ts __test__/volume-backups/restore-security.test.ts __test__/server/container-resource-stats-access.test.ts - 28 tests passed; on the old code the three new tests fail with "expected 101 to be less than or equal to 100" (102 for monitoring). Full run CI=true bunx vitest run --config __test__/vitest.config.ts: 2055 passed, 1 skipped, 8 failed, all in __test__/deploy/application.real.test.ts and __test__/setup/monitoring-setup.real.test.ts because the Docker Desktop socket is missing (connect ECONNREFUSED /Users/agent/.docker/run/docker.sock). bun run typecheck - 4/4 packages clean. bun run format-and-lint - 0 errors (33 warnings in other files, none in the changed files). A temporary vitest audit with toSQL (removed before the commit) checked the other nested application relations found by grep: they peak at 50 arguments.
- Limitations: the queries were not run against a live database; the *.real.test.ts tests were not verified without a local Docker; nothing was pushed or deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agentHits added a commit that referenced this pull request Oct 6, 2026
Что:
- findDeploymentById берёт из трёх вложенных связей application (у самого деплоя, у schedule и у volumeBackup) только serverId: другие поля этих связей вызывающий код не читает.
- Проверка восстановления volume backup (assertVolumeRestoreObjectBound) берёт из связей application и compose только appName.
- Поиск preview-деплоя в monitoring-access берёт из связи application только applicationId и serverId.
- Новый тестовый хелпер __test__/helpers/postgres-function-args.ts собирает настоящий SQL через drizzle.mock с реальной схемой и считает аргументы json_build_array. Для каждого из трёх запросов добавлен тест, который проверяет, что аргументов не больше 100.
Зачем:
- В таблице application 101 колонка. Drizzle кладёт все выбранные колонки вложенной связи в один вызов json_build_array, а Postgres принимает не больше 100 аргументов и отвечает ошибкой 54023 "cannot pass more than 100 arguments to a function".
- Из-за findDeploymentById не работали WebSocket логов деплоя (закрывался молча), deployment.readLogs, killProcess и removeDeployment, откат через rollback и создание rollback при деплое с rollback registry. Удаление старых rollback молча пропускалось.
- Из-за проверки восстановления не запускалось восстановление volume backup.
- Поиск preview-деплоя выполняется для каждого имени, которое не нашлось среди application. Поэтому мониторинг compose, баз данных и preview-деплоев (WebSocket docker stats, user.getContainerMetrics) отвечал ошибкой.
- Upstream уже сужал связи в findDeploymentById (97885ee), но при слиянии upstream 5a1d8ea (2026-10-01) конфликт разрешился в пользу application: true.
Риски:
- Если код начнёт читать из этих связей другие поля, их там не будет. Typecheck это ловит: при выборе appName вместо serverId tsc падает в listen-deployment.ts.
- backup.listBackupFiles в AgentHits-Dev падает с той же ошибкой. Его чинит открытый PR #6, здесь он не менялся. В тесте PR #6 своя копия подсчёта аргументов, после слияния её можно заменить общим хелпером.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/deployment/find-deployment-by-id.test.ts __test__/volume-backups/restore-security.test.ts __test__/server/container-resource-stats-access.test.ts - 28 тестов прошли; на старом коде три новых теста падают с "expected 101 to be less than or equal to 100" (для monitoring - 102). Полный прогон CI=true bunx vitest run --config __test__/vitest.config.ts: 2055 тестов прошли, 1 пропущен, 8 упали только в __test__/deploy/application.real.test.ts и __test__/setup/monitoring-setup.real.test.ts из-за отсутствия сокета Docker Desktop (connect ECONNREFUSED /Users/agent/.docker/run/docker.sock). bun run typecheck - 4/4 пакета без ошибок. bun run format-and-lint - 0 ошибок (33 предупреждения в других файлах, в изменённых файлах их нет). Временный vitest-аудит через toSQL (удалён перед коммитом) проверил остальные вложенные связи с application из grep: у них не больше 50 аргументов.
- Ограничения: запросы не выполнялись против живой базы; *.real.test.ts без локального Docker не проверены; ничего не пушилось и не выкатывалось.

What:
- findDeploymentById loads only serverId from its three nested application relations (on the deployment itself, on schedule and on volumeBackup); callers read no other field from them.
- The volume backup restore check (assertVolumeRestoreObjectBound) loads only appName from the application and compose relations.
- The preview deployment lookup in monitoring-access loads only applicationId and serverId from the application relation.
- A new test helper, __test__/helpers/postgres-function-args.ts, compiles the real SQL with drizzle.mock and the real schema and counts json_build_array arguments. Each of the three queries gets a test that checks there are no more than 100.
Why:
- The application table has 101 columns. Drizzle puts every selected column of a nested relation into one json_build_array call, and Postgres accepts at most 100 arguments and fails with 54023 "cannot pass more than 100 arguments to a function".
- Because of findDeploymentById, the deployment log WebSocket (closed silently), deployment.readLogs, killProcess and removeDeployment, rolling back, and rollback creation during deploys with a rollback registry all failed. Removing old rollbacks was silently skipped.
- Because of the restore check, a volume backup restore could not start.
- The preview deployment lookup runs for every name that is not found among applications. Monitoring for compose services, databases and preview deployments (the docker stats WebSocket, user.getContainerMetrics) therefore failed.
- Upstream had already narrowed the relations in findDeploymentById (97885ee), but the upstream merge 5a1d8ea (2026-10-01) resolved the conflict in favour of application: true.
Risks:
- Code that starts reading other fields from these relations will not find them there. Typecheck catches this: selecting appName instead of serverId makes tsc fail in listen-deployment.ts.
- backup.listBackupFiles fails with the same error in AgentHits-Dev. Open PR #6 fixes it, so it is unchanged here. The PR #6 test has its own copy of the argument counter, which can switch to the shared helper after both are merged.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts __test__/deployment/find-deployment-by-id.test.ts __test__/volume-backups/restore-security.test.ts __test__/server/container-resource-stats-access.test.ts - 28 tests passed; on the old code the three new tests fail with "expected 101 to be less than or equal to 100" (102 for monitoring). Full run CI=true bunx vitest run --config __test__/vitest.config.ts: 2055 passed, 1 skipped, 8 failed, all in __test__/deploy/application.real.test.ts and __test__/setup/monitoring-setup.real.test.ts because the Docker Desktop socket is missing (connect ECONNREFUSED /Users/agent/.docker/run/docker.sock). bun run typecheck - 4/4 packages clean. bun run format-and-lint - 0 errors (33 warnings in other files, none in the changed files). A temporary vitest audit with toSQL (removed before the commit) checked the other nested application relations found by grep: they peak at 50 arguments.
- Limitations: the queries were not run against a live database; the *.real.test.ts tests were not verified without a local Docker; nothing was pushed or deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@agentHits
agentHits merged commit 4ddea00 into AgentHits-Dev Oct 6, 2026
8 checks passed
@agentHits
agentHits deleted the fix/s3-backups branch October 6, 2026 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant