Files
restic/internal/backend/sftp/sftp_test.go
T
Eyüp Can Akman 62cf574fd8 sftp: Use mode 0700 for repository directories
The SFTP backend created repository directories with pkg/sftp's Mkdir
and MkdirAll, which take no mode argument, so the directories inherited
the SFTP server's umask instead of the 0700 used for local
repositories. Set the mode of each directory the backend creates.
2026-05-31 12:40:26 +03:00

127 lines
3.0 KiB
Go

package sftp_test
import (
"context"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"testing"
"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/backend/sftp"
"github.com/restic/restic/internal/backend/test"
"github.com/restic/restic/internal/errors"
rtest "github.com/restic/restic/internal/test"
)
func findSFTPServerBinary() string {
for _, dir := range strings.Split(rtest.TestSFTPPath, ":") {
testpath := filepath.Join(dir, "sftp-server")
_, err := os.Stat(testpath)
if !errors.Is(err, os.ErrNotExist) {
return testpath
}
}
return ""
}
var sftpServer = findSFTPServerBinary()
func testConfig(path string) sftp.Config {
return sftp.Config{
Path: path,
Command: fmt.Sprintf("%q -e", sftpServer),
Connections: 5,
}
}
func newTestSuite(t testing.TB) *test.Suite[sftp.Config] {
return &test.Suite[sftp.Config]{
// NewConfig returns a config for a new temporary backend that will be used in tests.
NewConfig: func() (*sftp.Config, error) {
dir := rtest.TempDir(t)
t.Logf("create new backend at %v", dir)
cfg := testConfig(dir)
return &cfg, nil
},
Factory: sftp.NewFactory(),
}
}
func TestBackendSFTP(t *testing.T) {
defer func() {
if t.Skipped() {
rtest.SkipDisallowed(t, "restic/backend/sftp.TestBackendSFTP")
}
}()
if sftpServer == "" {
t.Skip("sftp server binary not found")
}
newTestSuite(t).RunTests(t)
}
func BenchmarkBackendSFTP(t *testing.B) {
if sftpServer == "" {
t.Skip("sftp server binary not found")
}
newTestSuite(t).RunBenchmarks(t)
}
func TestCreateSetsDirPermissions(t *testing.T) {
if sftpServer == "" {
t.Skip("sftp server binary not found")
}
cfg := testConfig(filepath.Join(rtest.TempDir(t), "repo"))
be, err := sftp.Create(context.Background(), cfg, func(string, ...interface{}) {})
rtest.OK(t, err)
defer func() { rtest.OK(t, be.Close()) }()
rtest.OK(t, filepath.WalkDir(cfg.Path, func(name string, d fs.DirEntry, err error) error {
if err != nil || !d.IsDir() {
return err
}
fi, err := d.Info()
if err != nil {
return err
}
if mode := fi.Mode().Perm(); mode != 0o700 {
return fmt.Errorf("directory %v has mode %o, want 700", name, mode)
}
return nil
}))
}
func TestSaveSetsDirPermissions(t *testing.T) {
if sftpServer == "" {
t.Skip("sftp server binary not found")
}
cfg := testConfig(filepath.Join(rtest.TempDir(t), "repo"))
be, err := sftp.Create(context.Background(), cfg, func(string, ...interface{}) {})
rtest.OK(t, err)
defer func() { rtest.OK(t, be.Close()) }()
// Remove a data subdirectory so that Save has to recreate it.
subdir := filepath.Join(cfg.Path, "data", "01")
rtest.OK(t, os.Remove(subdir))
data := []byte("test data")
h := backend.Handle{Type: backend.PackFile, Name: "0100000000000000000000000000000000000000000000000000000000000000"}
rtest.OK(t, be.Save(context.Background(), h, backend.NewByteReader(data, be.Hasher())))
fi, err := os.Stat(subdir)
rtest.OK(t, err)
rtest.Equals(t, os.FileMode(0o700), fi.Mode().Perm())
}