| 438 | } |
| 439 | |
| 440 | func TestWriteFile_PreservesPermissions(t *testing.T) { |
| 441 | t.Parallel() |
| 442 | |
| 443 | if runtime.GOOS == "windows" { |
| 444 | t.Skip("file permissions are not reliably supported on Windows") |
| 445 | } |
| 446 | |
| 447 | dir := t.TempDir() |
| 448 | logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug) |
| 449 | osFs := afero.NewOsFs() |
| 450 | api := agentfiles.NewAPI(logger, osFs, nil) |
| 451 | |
| 452 | path := filepath.Join(dir, "script.sh") |
| 453 | err := afero.WriteFile(osFs, path, []byte("#!/bin/sh\necho hello\n"), 0o755) |
| 454 | require.NoError(t, err) |
| 455 | |
| 456 | info, err := osFs.Stat(path) |
| 457 | require.NoError(t, err) |
| 458 | require.Equal(t, os.FileMode(0o755), info.Mode().Perm()) |
| 459 | |
| 460 | ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) |
| 461 | defer cancel() |
| 462 | |
| 463 | // Overwrite the file with new content. |
| 464 | w := httptest.NewRecorder() |
| 465 | r := httptest.NewRequestWithContext(ctx, http.MethodPost, |
| 466 | fmt.Sprintf("/write-file?path=%s", path), |
| 467 | bytes.NewReader([]byte("#!/bin/sh\necho world\n"))) |
| 468 | api.Routes().ServeHTTP(w, r) |
| 469 | require.Equal(t, http.StatusOK, w.Code) |
| 470 | |
| 471 | data, err := afero.ReadFile(osFs, path) |
| 472 | require.NoError(t, err) |
| 473 | require.Equal(t, "#!/bin/sh\necho world\n", string(data)) |
| 474 | |
| 475 | info, err = osFs.Stat(path) |
| 476 | require.NoError(t, err) |
| 477 | require.Equal(t, os.FileMode(0o755), info.Mode().Perm(), |
| 478 | "write_file should preserve the original file's permissions") |
| 479 | } |
| 480 | |
| 481 | func TestEditFiles(t *testing.T) { |
| 482 | t.Parallel() |