Repository navigation
feat: config backup and restore (WI-1721) - #247
Merged
Merged
Conversation
Collaborator
Author
|
Review of 254635a: 2 blockers. GitHub Checks run locally:
Blockers
Import validation: sound
Nits
|
Collaborator
Author
|
Re-review of d1d7c78: no blockers (CI pending). GitHub Both blockers are fixed:
The restore merge is sound.
The other two nits from my first review are also fixed:
Checks run locally:
Nits
|
thedancingdeveloper
enabled auto-merge
October 20, 2026 16:44
Add GET /api/config/backup, POST /api/config/backup/preview and POST /api/config/backup/restore, plus a Backup & restore page in Settings. A backup is a `[backup]` header over the `[config]` table, so it is a readable config.toml with a provenance envelope. The default export masks every stored secret as `********` and says `secrets_included = false`; `?secrets=true` is an explicit opt-in that writes the real values and labels the file. On restore the mask is a keep token: a masked secret keeps the value the target already holds, and a mask with nothing behind it leaves the setting unset and is reported as a warning rather than written through as a literal password. A secret absent from the backup is cleared, because a restore replaces the file layer. Nothing is written unless the document parses, normalizes and validates; unknown keys, newer envelope or config versions and invalid values are refused with the reason and leave the config and the file untouched. The preview takes the same path up to the commit, so the UI can show the summary, kept secrets, warnings and restart-required settings before the operator confirms. Live settings are pushed into the running queue manager after the save. Move the shared secret masking out of the handlers into `nzb_core::config_backup` so the settings endpoint and the backup scrub exactly the same fields. Bump nzb-core to 0.2.22 for the new public module. Tests: unit coverage for masking, merge and validation; API tests for the no-secret export, keep-on-mask, replace-with-secrets, fresh-install warnings, refusals leaving state untouched and auth; frontend tests for the download, preview gating, confirmation and failure paths.
A masked export promised to be safe to share, but it left RSS feed URLs untouched. Indexers carry the account key in the URL query, so every masked backup published each indexer credential. Mask where a secret can actually live: - RSS feed URLs: the query string and any userinfo are replaced, keeping scheme, host and path so a restore can still match the feed. A masked URL keeps the stored one only for the same feed; with nothing to keep the feed is dropped with a warning rather than saved with `********`. - notifications.ntfy_topic, which is a bearer secret on a public ntfy server. - otel.endpoint, logs_endpoint and metrics_endpoint userinfo. After the merge, validate() refuses any remaining mask, so a masked proxy URL pointing at a different host is cleared with a warning instead of being written through literally. Also tighten the envelope: `backup_version` now defaults to 0 rather than 1, so a document that omits it is refused instead of read as current, and the header and top-level tables reject unknown keys. A TOML syntax error is reported with line and column but without echoing the offending source line, which could otherwise copy a password out of a secrets-included file into the 400 response. Drop the regenerated windows-sys downgrades from Cargo.lock; the nzb-core 0.2.22 line is the only change. Tests: RSS, ntfy-topic and OTel canaries in the core and API suites; keep-on-match and drop-without-match feed restores; masked-proxy mismatch; envelope version/key refusals; parse-error redaction.
thedancingdeveloper
force-pushed
the
wi-1721-backup-restore
branch
from
October 20, 2026 19:03
d1d7c78 to
8631f18
Compare
CodeQL flags a test panic message that interpolates the canary it is checking for as cleartext logging of sensitive information. Report which credential leaked by field name instead; the assertions stay as strict.
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.
WI-1721: export and import of settings through the API and the UI, validated on import, with secrets masked. Written by a DeepSeek worker; the handoff is on WI-1721.
🤖 Generated with Claude Code