detached 89277e3

fix(snapshot): address restore review follow-ups

commit
89277e323607e170fc0234b3006ac13f1f89ba3c
author
brice · · 2026-07-06 13:54 UTC
parent
f4b9a61
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +11 -0
M internal/platform/proc_linux.go +3 -0
@@ -12,6 +12,9 @@ func ProcessCwd(pid int) (string, error) {
1212 }
1313
1414 func processCwd(root string, pid int) (string, error) {
15+ if pid <= 0 {
16+ return "", fmt.Errorf("process cwd: invalid pid %d", pid)
17+ }
1518 return os.Readlink(fmt.Sprintf("%s/%d/cwd", root, pid))
1619 }
1720
@@ -12,6 +12,9 @@ func ProcessCwd(pid int) (string, error) {
12 }12 }
13 13
14 func processCwd(root string, pid int) (string, error) {14 func processCwd(root string, pid int) (string, error) {
15+ if pid <= 0 {
16+ return "", fmt.Errorf("process cwd: invalid pid %d", pid)
17+ }
15 return os.Readlink(fmt.Sprintf("%s/%d/cwd", root, pid))18 return os.Readlink(fmt.Sprintf("%s/%d/cwd", root, pid))
16 }19 }
17 20
M internal/platform/process_linux_test.go +6 -0
@@ -9,6 +9,12 @@ import (
99 "testing"
1010 )
1111
12+func TestProcessCwdRejectsInvalidPID(t *testing.T) {
13+ if _, err := processCwd("/proc", 0); err == nil {
14+ t.Fatal("processCwd accepted invalid pid")
15+ }
16+}
17+
1218 func TestProcessArgv(t *testing.T) {
1319 argv, err := ProcessArgv(os.Getpid())
1420 if err != nil {
@@ -9,6 +9,12 @@ import (
9 "testing"9 "testing"
10 )10 )
11 11
12+func TestProcessCwdRejectsInvalidPID(t *testing.T) {
13+ if _, err := processCwd("/proc", 0); err == nil {
14+ t.Fatal("processCwd accepted invalid pid")
15+ }
16+}
17+
12 func TestProcessArgv(t *testing.T) {18 func TestProcessArgv(t *testing.T) {
13 argv, err := ProcessArgv(os.Getpid())19 argv, err := ProcessArgv(os.Getpid())
14 if err != nil {20 if err != nil {
M internal/usecase/daemon/snapshot_restore_test.go +2 -0
@@ -205,6 +205,8 @@ func TestRestoreSnapshotsProcessCommandWriteFailureIsNonFatal(t *testing.T) {
205205 d.ApplyConfig(domain.Config{Snapshot: domain.SnapshotConfig{RestoreProcessesSet: true, RestoreProcesses: []string{"pi"}}})
206206
207207 require.NoError(t, d.restoreSession(context.Background(), snapcodec.Session{Name: "agent", Tabs: []snapcodec.Tab{{Cols: 80, Rows: 24, Tree: layout.NewTree("pane-1"), Panes: []snapcodec.Pane{{ID: "pane-1", Cwd: "/tmp", Process: proc}}}}}))
208+ require.Len(t, factory.opens, 1)
209+ require.Equal(t, []string{"pi --resume abc123\n"}, factory.opens[0].pty.writes)
208210 }
209211
210212 func TestRestoreSnapshotsOpensCollapsedStackPanesWithValidPTYSize(t *testing.T) {
@@ -205,6 +205,8 @@ func TestRestoreSnapshotsProcessCommandWriteFailureIsNonFatal(t *testing.T) {
205 d.ApplyConfig(domain.Config{Snapshot: domain.SnapshotConfig{RestoreProcessesSet: true, RestoreProcesses: []string{"pi"}}})205 d.ApplyConfig(domain.Config{Snapshot: domain.SnapshotConfig{RestoreProcessesSet: true, RestoreProcesses: []string{"pi"}}})
206 206
207 require.NoError(t, d.restoreSession(context.Background(), snapcodec.Session{Name: "agent", Tabs: []snapcodec.Tab{{Cols: 80, Rows: 24, Tree: layout.NewTree("pane-1"), Panes: []snapcodec.Pane{{ID: "pane-1", Cwd: "/tmp", Process: proc}}}}}))207 require.NoError(t, d.restoreSession(context.Background(), snapcodec.Session{Name: "agent", Tabs: []snapcodec.Tab{{Cols: 80, Rows: 24, Tree: layout.NewTree("pane-1"), Panes: []snapcodec.Pane{{ID: "pane-1", Cwd: "/tmp", Process: proc}}}}}))
208+ require.Len(t, factory.opens, 1)
209+ require.Equal(t, []string{"pi --resume abc123\n"}, factory.opens[0].pty.writes)
208 }210 }
209 211
210 func TestRestoreSnapshotsOpensCollapsedStackPanesWithValidPTYSize(t *testing.T) {212 func TestRestoreSnapshotsOpensCollapsedStackPanesWithValidPTYSize(t *testing.T) {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close