Description
cmd/restore.go ignores the error/no-rows case when looking up a snapshot:
id := args[0]
database := db.InitDB()
var path string
database.QueryRow("SELECT path FROM snapshots WHERE id=?", id).Scan(&path)
err := snapshot.RestoreSnapshot(path)
If id doesn't exist in the DB, Scan returns sql.ErrNoRows, which is
discarded — path stays "". Execution continues straight into
RestoreSnapshot("").
RestoreSnapshot (internal/snapshot/snapshot.go) does not check that
path is valid before Phase 1, which deletes every top-level file/dir in the
current directory (except .eko) concurrently via os.RemoveAll. Phase 2
then calls util.CopyDir("", ".") with an empty source.
Repro
eko init
eko save
eko restore not-a-real-id
Expected: a clear "snapshot not found" error, nothing touched.
Actual: the current directory's contents get deleted first, then a copy from
an empty path is attempted — no safe recovery path if that second step also
misbehaves.
Suggested fix
Check the query result before calling RestoreSnapshot:
row := database.QueryRow("SELECT path FROM snapshots WHERE id=?", id)
if err := row.Scan(&path); err != nil {
if err == sql.ErrNoRows {
return fmt.Errorf("no snapshot found with id %q", id)
}
return err
}
Return the error from Run (or use RunE) instead of proceeding.
Description
cmd/restore.goignores the error/no-rows case when looking up a snapshot:If
iddoesn't exist in the DB,Scanreturnssql.ErrNoRows, which isdiscarded —
pathstays"". Execution continues straight intoRestoreSnapshot("").RestoreSnapshot(internal/snapshot/snapshot.go) does not check thatpathis valid before Phase 1, which deletes every top-level file/dir in thecurrent directory (except
.eko) concurrently viaos.RemoveAll. Phase 2then calls
util.CopyDir("", ".")with an empty source.Repro
Expected: a clear "snapshot not found" error, nothing touched.
Actual: the current directory's contents get deleted first, then a copy from
an empty path is attempted — no safe recovery path if that second step also
misbehaves.
Suggested fix
Check the query result before calling
RestoreSnapshot:Return the error from
Run(or useRunE) instead of proceeding.