- first_time_install.sh: verify chown/chmod succeed and the final
owner/group/mode on config_secrets.json before reporting success;
exit with a clear error otherwise instead of swallowing failures.
- api_v3.py: replace the predictable .writetest probe with an
exclusive NamedTemporaryFile to avoid a race with concurrent
resolvers; log the preferred/fallback export path and OSError when
falling back to the reinstall-deleted directory.
- api_v3.py: mark a restore as failed when plugin reinstalls fail,
even if file restoration itself succeeded, so the endpoint no longer
reports HTTP 200 success on a partial restore.
- api_v3.py: stringify plugin IDs before joining them into the error
message so a malformed backup's non-string plugin_id can't raise a
TypeError and mask the detailed response.
- backup_manager.py / api_v3.py: stop putting raw exception text (originating
from a user-controlled backup file) into restore results returned to
the client; log full details server-side instead. Addresses the
CodeQL "stack trace information exposure" alert.
- test coverage: add a test for get_plugin_info() resolving a
manifest id, and assert the disabled restore_wifi path also skips
and omits ytm_auth.json.