feat: Add import and export functionality in surge#362
feat: Add import and export functionality in surge#362junaid2005p wants to merge 11 commits intomainfrom
Conversation
Binary Size Analysis
|
| if opts.Replace { | ||
| if err := clearExistingState(); err != nil { | ||
| return nil, err | ||
| } | ||
| } | ||
|
|
||
| settingsSaved := false | ||
| if payload.Settings != nil { | ||
| if payload.Settings.General.DefaultDownloadDir != "" && rootDir != "" { | ||
| payload.Settings.General.DefaultDownloadDir = utils.EnsureAbsPath(rootDir) | ||
| } | ||
| if err := config.SaveSettings(payload.Settings); err != nil { | ||
| return nil, err | ||
| } | ||
| settingsSaved = true | ||
| } | ||
|
|
||
| logsRestored, err := restoreLogFiles(opened.Reader, manifest, opts.Replace) | ||
| if err != nil { | ||
| return nil, err |
There was a problem hiding this comment.
Non-atomic replace leaves Surge in a partially-migrated state
In Replace mode, clearExistingState() wipes the download database (line 219), then settings are written to disk (line 229), and only then are log files and downloads restored. If restoreLogFiles or any iteration of the download-import loop returns an error, the function exits early — leaving the user with a cleared history and new settings applied but zero downloads imported.
Since the database clear is irreversible and happens before any restoration, a transient error (e.g. disk full during partial-file restore) creates unrecoverable data loss for the user. Moving SaveSettings to after all downloads and logs are successfully restored narrows this window significantly:
// Move settings save to after successful restoration
logsRestored, err := restoreLogFiles(opened.Reader, manifest, opts.Replace)
if err != nil {
return nil, err
}
// ... import loop ...
if payload.Settings != nil {
// apply settings only after all other steps succeeded
if err := config.SaveSettings(payload.Settings); err != nil {
return nil, err
}
settingsSaved = true
}Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/backup/backup.go
Line: 218-237
Comment:
**Non-atomic replace leaves Surge in a partially-migrated state**
In Replace mode, `clearExistingState()` wipes the download database (line 219), then settings are written to disk (line 229), and only then are log files and downloads restored. If `restoreLogFiles` or any iteration of the download-import loop returns an error, the function exits early — leaving the user with a **cleared history and new settings applied but zero downloads imported**.
Since the database clear is irreversible and happens before any restoration, a transient error (e.g. disk full during partial-file restore) creates unrecoverable data loss for the user. Moving `SaveSettings` to after all downloads and logs are successfully restored narrows this window significantly:
```go
// Move settings save to after successful restoration
logsRestored, err := restoreLogFiles(opened.Reader, manifest, opts.Replace)
if err != nil {
return nil, err
}
// ... import loop ...
if payload.Settings != nil {
// apply settings only after all other steps succeeded
if err := config.SaveSettings(payload.Settings); err != nil {
return nil, err
}
settingsSaved = true
}
```
How can I resolve this? If you propose a fix, please make it concise.
Greptile Summary
This PR adds import/export (backup/restore) functionality to Surge via new CLI commands (
export,import), a TUI Data Transfer panel, HTTP API endpoints (/data/export,/data/import/preview,/data/import/apply), and abackuppackage with a staged two-phase preview→apply workflow.The three major security issues raised in the previous review (predictable session ID, missing upload size limit, relative path traversal) are all addressed in this revision.
Confidence Score: 4/5
Safe to merge for most paths; Replace-mode import has a known data-integrity ordering issue from the prior review that remains unresolved.
All three prior security findings (path traversal, upload limit, predictable session ID) are fixed. New findings are P2 only (memory efficiency in verifyManifestFiles, silent marshal error, missing LeavePaused TUI toggle). Score stays at 4 because the non-atomic Replace ordering (clear DB → save settings → restore) is still present and represents a real data-loss risk for Replace-mode imports that abort midway.
internal/backup/backup.go — ApplyImport ordering in Replace mode; verifyManifestFiles memory usage
Important Files Changed
Prompt To Fix All With AI
Reviews (3): Last reviewed commit: "fix: fixed COdeQL issues" | Re-trigger Greptile