Repository navigation
fix: bind kept stored secrets to their saved endpoints - #29
Merged
Merged
Conversation
Что: - Общий хелпер assertStoredSecretTargetUnchanged: если запрос оставляет сохраненный секрет (плейсхолдер, пустое или отсутствующее значение), все поля адреса/хоста/логина должны совпадать с сохраненными, иначе BAD_REQUEST "Re-enter the <secret> to change <fields>". - Vault-провайдеры: mergeVaultProviderConfig (update и testConnection) привязывает сохраненные креды к url/siteUrl/apiUrl/vaultUri/endpoint/region/tenantId/clientId/accessKeyId; accessKeyId для aws и aws-parameter-store теперь маскируется. - Registry: updateRegistry не делает docker login с сохраненным паролем на новый registryUrl/username; organizationId убран из apiUpdateRegistry. - Уведомления: email (smtpServer/smtpPort/username), gotify и ntfy (serverUrl), custom (endpoint при сохраненных заголовках); updateEmail теперь возвращает понятное сообщение TRPCError. - AI: сохраненный apiKey нельзя отправить на новый apiUrl. - GitLab/Gitea: смена URL или client id требует заново ввести secret; при смене URL OAuth-токены сбрасываются, провайдер нужно авторизовать заново. В форму редактирования GitLab добавлено необязательное поле Application Secret. - DNS: accessKeyId (route53) и apiKey (porkbun) маскируются, плейсхолдер восстанавливается при update/test. Зачем: - Пользователь с правом редактирования, но без доступа к секрету, мог направить сохраненный токен или пароль на свой хост и перехватить его. Риски: - Смена адреса, логина или региона существующей записи теперь требует повторного ввода секрета; для GitLab/Gitea после смены URL нужна повторная авторизация. - Записи со старыми ненормализованными адресами сравниваются и по сырому значению, но редкие расхождения формата потребуют повторного ввода секрета. Проверки: - Команды и результаты: `CI=true bunx vitest run --config __test__/vitest.config.ts` по 7 новым/измененным файлам: 45 passed; папки env, dns, registry, notification, ai, security, settings, permissions и провайдеров Git: 68 файлов, 785 passed; все новые тесты (28) падают на коде origin/AgentHits-Dev (исходники временно возвращены через checkout); полный прогон: 237 файлов passed, падает только application.real.test.ts (нет Docker); `bun run typecheck`: exit 0; `bunx biome check` по 18 измененным файлам: 0 ошибок. - Ограничения: UI-формы и реальные внешние провайдеры (vault, registry, SMTP, GitLab/Gitea) вручную не проверялись. What: - Shared helper assertStoredSecretTargetUnchanged: when a request keeps a stored secret (placeholder, blank or omitted value), every endpoint/host/username field must equal the stored value, otherwise BAD_REQUEST "Re-enter the <secret> to change <fields>". - Vault providers: mergeVaultProviderConfig (update and testConnection) binds stored credentials to url/siteUrl/apiUrl/vaultUri/endpoint/region/tenantId/clientId/accessKeyId; accessKeyId is now masked for aws and aws-parameter-store. - Registry: updateRegistry no longer runs docker login with the stored password against a new registryUrl/username; organizationId is removed from apiUpdateRegistry. - Notifications: email (smtpServer/smtpPort/username), gotify and ntfy (serverUrl), custom (endpoint while headers are kept); updateEmail now returns the TRPCError message. - AI: a stored apiKey cannot be sent to a new apiUrl. - GitLab/Gitea: changing the URL or client id requires the secret again; a URL change drops OAuth tokens so the provider must be authorized again. The GitLab edit form gets an optional Application Secret field. - DNS: route53 accessKeyId and porkbun apiKey are masked; the placeholder is restored on update/test. Why: - A user who can edit a record but cannot read its secret could point the stored token or password at a host they control and capture it. Risks: - Changing the address, username or region of an existing record now requires entering the secret again; GitLab/Gitea need re-authorization after a URL change. - Rows with older non-normalized addresses also match on the raw value, but rare format differences will ask for the secret again. Checks: - Commands and results: `CI=true bunx vitest run --config __test__/vitest.config.ts` on the 7 new/changed files: 45 passed; env, dns, registry, notification, ai, security, settings, permissions and Git provider folders: 68 files, 785 passed; all 28 new tests fail on origin/AgentHits-Dev code (sources temporarily restored with checkout); full run: 237 files passed, only application.real.test.ts fails (no Docker); `bun run typecheck`: exit 0; `bunx biome check` on the 18 changed files: 0 errors. - Limitations: UI forms and real external providers (vault, registry, SMTP, GitLab/Gitea) were not checked manually. 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?
A stored secret could be reused with a destination chosen by the caller. Update and test procedures refill the stored secret when the request carries the masked placeholder (or leaves the secret blank/omitted), but they took endpoint, host and username fields from the request. A user who can edit a record but cannot read its secret could point it at a host they control and capture the secret.
New rule, enforced by a shared helper
assertStoredSecretTargetUnchanged(packages/server/src/utils/security/redaction.ts): when the request keeps the stored secret, every endpoint/host/username field must equal the stored value; otherwise the request fails withBAD_REQUEST"Re-enter the to change ".mergeVaultProviderConfig(used byupdateandtestConnection) binds kept credentials tourl/siteUrl+clientId/region+endpoint+accessKeyId/vaultUri+tenantId+clientId/apiUrl. AWS and AWS Parameter StoreaccessKeyIdis now masked as well.updateRegistryno longer runsdocker loginwith the stored password against a newregistryUrlorusername.organizationIdis removed fromapiUpdateRegistry.smtpServer,smtpPort,usernamewith the stored password), Gotify (serverUrlwith the stored app token), ntfy (serverUrlwith the stored access token), custom (endpointwhile stored header values are kept).updateEmailnow passes theTRPCErrormessage through instead of a generic one.apiKeycannot be sent to a newapiUrl.accessKeyIdand PorkbunapiKeyare masked; the placeholder is restored on update and test as before.What changes for users:
The S3 destination router is not touched here.
Checks
CI=true bunx vitest run --config __test__/vitest.config.tson the 7 new/changed test files: 45 passed.origin/AgentHits-Devsources (checked by temporarily restoring the source files withgit checkout origin/AgentHits-Dev -- <files>).application.real.test.tsfails locally (no Docker socket), as expected.bun run typecheck: exit 0.bunx biome checkon the 18 changed files: 0 errors.Rollout notes
BAD_REQUEST; re-enter the secret in the form.********; saving the form unchanged keeps the stored value.🤖 Generated with Claude Code