Skip to content

fix: redact secrets in nested relations of backup, schedule and certificate reads - #25

Merged
agentHits merged 1 commit into
AgentHits-Devfrom
fix/nested-relation-secrets
Oct 7, 2026
Merged

agentHits merged 1 commit into
AgentHits-Devfrom
fix/nested-relation-secrets

Conversation

@agentHits

Copy link
Copy Markdown
Collaborator

What is this PR about?

Several read procedures returned nested relations without redaction, so anyone with read access to the service got secrets of related records:

  • volumeBackups.one: full postgres/mysql/mariadb/mongo/redis/libsql rows (databasePassword, databaseRootPassword, env), the full compose row (env, composeFile, customGitUrl credentials, refreshToken) and environment/project env.
  • compose.one and compose.delete: backup metadata with mariadb/mongo databasePassword and mysql databaseRootPassword.
  • backup.one: the compose relation (env, composeFile, customGitUrl credentials, refreshToken).
  • schedule.one and schedule.list: the full compose row, environment/project env, and the server row (command, metricsConfig.server.token).
  • certificate.all: the server row (command, metrics token).
  • user.getBackups: destination accessKey and secretAccessKey.

Changes:

  • New shared helper redactServiceRelationSecrets in packages/server/src/utils/security/redaction.ts. It redacts a record's nested application/compose (deployable helpers plus composeFile), database relations (database helper) and server. Shared env is always redacted, because no UI reads it from these responses. redactBackupScheduleSecrets now uses it, so backup.one also redacts the compose relation.
  • volumeBackups.one, schedule.one and schedule.list return their records through the new helper. schedule.create is not touched.
  • The compose router's redactComposeSecrets maps backups through redactBackupScheduleSecrets. This covers compose.one and compose.delete.
  • certificate.all maps each server through the existing redactServer.
  • user.getBackups excludes the destination accessKey/secretAccessKey columns, like findBackupById already does.

UI impact: none expected. The volume-backup and schedule forms only read top-level fields. The backup edit form loads metadata from backup.one, which was already redacted, and backup.update keeps the stored password when it gets the placeholder. The certificate list reads only server.name and server.ipAddress. The web-server backup list reads only destination.name.

Checks

  • CI=true bunx vitest run --config __test__/vitest.config.ts on the new and changed tests: all 9 new tests pass. All 9 fail when the source files are reverted to origin/AgentHits-Dev, with assertion failures (secrets present) rather than crashes.
  • Related folders security, schedule, backup, backups, volume-backups, certificate, compose, users: 73 files, 522 tests passed.
  • bun run typecheck: exit 0 for all packages.
  • bunx biome check on the 12 changed files: 0 errors.
  • Not checked: the UI in a browser.

Rollout notes

  • No migrations or config changes.
  • External API/MCP clients that read these nested fields (database passwords, compose env/file, server command/metrics token, destination keys) now get __DOKPLOY_REDACTED_SECRET__ or no field. The dedicated reveal/one endpoints of each resource are unchanged.

🤖 Generated with Claude Code

…ficate reads

Что:
- volumeBackups.one, schedule.one и schedule.list прогоняют вложенные сервисы, окружение, проект и сервер через новый общий помощник redactServiceRelationSecrets.
- backup.one теперь скрывает связанный compose (env, composeFile, учетные данные в customGitUrl, refreshToken); redactBackupScheduleSecrets использует тот же помощник.
- compose.one и compose.delete скрывают пароли в metadata бэкапов (mariadb/mongo databasePassword, mysql databaseRootPassword).
- certificate.all скрывает command и metrics token сервера через redactServer.
- user.getBackups больше не выбирает accessKey и secretAccessKey назначения.
Зачем:
- Эти процедуры чтения отдавали пароли баз данных, env, compose-файлы, токены и S3-ключи всем, у кого есть право чтения.
Риски:
- Скрытые поля теперь приходят как __DOKPLOY_REDACTED_SECRET__ или отсутствуют. UI их не читает: форма бэкапа берет metadata из backup.one (уже скрыто, update сохраняет placeholder), список сертификатов читает только name и ipAddress сервера. Внешние клиенты API, которые читали эти вложенные поля, получат placeholder.
Проверки:
- Команды и результаты: CI=true bunx vitest run --config __test__/vitest.config.ts по новым и измененным тестам — 9 новых тестов проходят и падают на origin/AgentHits-Dev (исходники временно возвращались через git checkout); папки security, schedule, backup, backups, volume-backups, certificate, compose, users — 73 файла, 522 теста прошли; bun run typecheck — exit 0; bunx biome check по 12 измененным файлам — 0 ошибок.
- Ограничения: UI в браузере не проверялся.

What:
- volumeBackups.one, schedule.one and schedule.list pass nested services, environment, project and server through a new shared helper, redactServiceRelationSecrets.
- backup.one now redacts the bound compose (env, composeFile, customGitUrl credentials, refreshToken); redactBackupScheduleSecrets uses the same helper.
- compose.one and compose.delete redact backup metadata passwords (mariadb/mongo databasePassword, mysql databaseRootPassword).
- certificate.all redacts the server command and metrics token with redactServer.
- user.getBackups no longer selects destination accessKey and secretAccessKey.
Why:
- These read procedures returned database passwords, env, compose files, tokens and S3 keys to anyone with read access.
Risks:
- Redacted fields now come back as __DOKPLOY_REDACTED_SECRET__ or are missing. The UI does not read them: the backup form loads metadata from backup.one (already redacted, update keeps the placeholder), the certificate list reads only the server name and ipAddress. External API clients that read these nested fields will get the placeholder.
Checks:
- Commands and results: CI=true bunx vitest run --config __test__/vitest.config.ts on the new and changed tests: the 9 new tests pass and fail on origin/AgentHits-Dev (sources temporarily restored with git checkout); folders security, schedule, backup, backups, volume-backups, certificate, compose, users: 73 files, 522 tests passed; bun run typecheck: exit 0; bunx biome check on the 12 changed files: 0 errors.
- Limitations: the UI was not checked in a browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@agentHits
agentHits merged commit 91d4419 into AgentHits-Dev Oct 7, 2026
8 checks passed
@agentHits
agentHits deleted the fix/nested-relation-secrets branch October 7, 2026 05:51
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