diff --git a/server/cmd/api/api/chromium_configure.go b/server/cmd/api/api/chromium_configure.go index 7d995314..928d3466 100644 --- a/server/cmd/api/api/chromium_configure.go +++ b/server/cmd/api/api/chromium_configure.go @@ -158,6 +158,11 @@ func (s *ApiService) ChromiumConfigure(ctx context.Context, request oapi.Chromiu if err != nil { return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error()), nil } + if spec.needsNav { + if err := stripProfileSessionRestore(preparedProfile); err != nil { + return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error()), nil + } + } if err := chromiumInstallPreparedProfile(preparedProfile); err != nil { return cfg500ConfigureStep(chromiumConfigureStepProfile, err.Error()), nil } @@ -564,6 +569,16 @@ func chromiumPrepareProfileArchive(profilePath string, strip int) (preparedDir s return preparedDir, cleanup, nil } +// stripProfileSessionRestore deletes the prepared profile's Default/Sessions so +// Chrome cannot restore its saved tabs after the restart and race the start_url +// navigation. Only the live copy is touched; the stored archive is unchanged. +func stripProfileSessionRestore(preparedDir string) error { + if err := os.RemoveAll(filepath.Join(preparedDir, "Default", "Sessions")); err != nil { + return fmt.Errorf("strip profile session restore: %w", err) + } + return nil +} + func chromiumInstallPreparedProfile(preparedDir string) error { if preparedDir == "" { return nil diff --git a/server/cmd/api/api/chromium_configure_test.go b/server/cmd/api/api/chromium_configure_test.go index e4f44f04..eac0e5f1 100644 --- a/server/cmd/api/api/chromium_configure_test.go +++ b/server/cmd/api/api/chromium_configure_test.go @@ -5,6 +5,8 @@ import ( "errors" "io" "mime/multipart" + "os" + "path/filepath" "strings" "testing" @@ -76,6 +78,24 @@ func TestChromiumStartURLSpec(t *testing.T) { require.NotEmpty(t, errs) } +func TestStripProfileSessionRestore(t *testing.T) { + prepared := t.TempDir() + sessions := filepath.Join(prepared, "Default", "Sessions") + require.NoError(t, os.MkdirAll(sessions, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(sessions, "Session_123"), []byte("tabs"), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(prepared, "Default", "Preferences"), []byte("{}"), 0o644)) + + require.NoError(t, stripProfileSessionRestore(prepared)) + + _, err := os.Stat(sessions) + require.True(t, os.IsNotExist(err)) + _, err = os.Stat(filepath.Join(prepared, "Default", "Preferences")) + require.NoError(t, err) + + // Absent Sessions directory is a no-op, not an error. + require.NoError(t, stripProfileSessionRestore(prepared)) +} + func TestChromiumValidateFlags(t *testing.T) { valid := `{"flags":["--kiosk"]}` plan, err := chromiumValidateFlags(&valid)