| 83 | } |
| 84 | |
| 85 | func TestSync_StatPermissionError(t *testing.T) { |
| 86 | if runtime.GOOS == "windows" { |
| 87 | t.Skip("permission-based test not reliable on Windows") |
| 88 | } |
| 89 | if os.Getuid() == 0 { |
| 90 | t.Skip("test requires non-root to trigger EACCES") |
| 91 | } |
| 92 | |
| 93 | tmpDir := t.TempDir() |
| 94 | restrictedDir := filepath.Join(tmpDir, "noaccess") |
| 95 | assert.NilError(t, os.Mkdir(restrictedDir, 0o700)) |
| 96 | targetFile := filepath.Join(restrictedDir, "secret.txt") |
| 97 | assert.NilError(t, os.WriteFile(targetFile, []byte("data"), 0o644)) |
| 98 | // Remove all permissions on the parent directory so stat on the child fails with EACCES. |
| 99 | assert.NilError(t, os.Chmod(restrictedDir, 0o000)) |
| 100 | t.Cleanup(func() { |
| 101 | // Restore permissions so t.TempDir() cleanup can remove it. |
| 102 | _ = os.Chmod(restrictedDir, 0o700) |
| 103 | }) |
| 104 | |
| 105 | client := &fakeLowLevelClient{ |
| 106 | containers: []container.Summary{{ID: "ctr1"}}, |
| 107 | } |
| 108 | tar := NewTar("proj", client) |
| 109 | |
| 110 | err := tar.Sync(t.Context(), "svc", []*PathMapping{ |
| 111 | {HostPath: targetFile, ContainerPath: "/app/secret.txt"}, |
| 112 | }) |
| 113 | |
| 114 | assert.ErrorContains(t, err, "permission denied") |
| 115 | assert.ErrorContains(t, err, "secret.txt") |
| 116 | assert.Equal(t, client.untarCount, 0, "should not attempt copy on stat error") |
| 117 | assert.Equal(t, len(client.execCmds), 0, "should not attempt delete on stat error") |
| 118 | } |
| 119 | |
| 120 | func TestSync_MixedPaths(t *testing.T) { |
| 121 | tmpDir := t.TempDir() |