]> ruderich.org/simon Gitweb - safcm/safcm.git/blobdiff - remote/sync/files_test.go
Use SPDX license identifiers
[safcm/safcm.git] / remote / sync / files_test.go
index 39714594382445369936666719d625d4351cd820..7a4ce260f487b21d956b60600c8d946e8074dd10 100644 (file)
@@ -1,17 +1,5 @@
-// Copyright (C) 2021  Simon Ruderich
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright (C) 2021-2024  Simon Ruderich
 
 package sync
 
@@ -36,7 +24,7 @@ func TestSyncFiles(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       defer os.Chdir(cwd)
+       defer os.Chdir(cwd) //nolint:errcheck
 
        err = os.RemoveAll("testdata")
        if err != nil {
@@ -81,26 +69,26 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                        },
                                },
                        },
@@ -165,26 +153,26 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                        },
                                },
                        },
@@ -220,12 +208,12 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                User:      "user",
                                                Uid:       1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                        },
                                },
                        },
@@ -244,12 +232,12 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Group:     "group",
                                                Gid:       1,
-                                               OrigGroup: "group",
                                        },
                                },
                        },
@@ -276,25 +264,25 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        "/": {
+                                               OrigGroup: "group",
                                                Path:      "/",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       0,
                                                Gid:       0,
-                                               OrigGroup: "group",
                                        },
                                        "/etc": {
+                                               OrigGroup: "group",
                                                Path:      "/etc",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       0,
                                                Gid:       0,
-                                               OrigGroup: "group",
                                        },
                                        "/tmp": {
+                                               OrigGroup: "group",
                                                Path:      "/tmp",
                                                Mode:      fs.ModeDir | 0777 | fs.ModeSticky,
                                                Uid:       0,
                                                Gid:       0,
-                                               OrigGroup: "group",
                                        },
                                },
                        },
@@ -318,32 +306,32 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger .",
                                                },
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir",
                                                },
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir/file",
                                                },
@@ -382,32 +370,32 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger .",
                                                },
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir",
                                                },
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir/file",
                                                },
@@ -472,32 +460,32 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger .",
                                                },
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir",
                                                },
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir/file",
                                                },
@@ -563,32 +551,32 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger .",
                                                },
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir",
                                                },
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir/file",
                                                },
@@ -650,32 +638,32 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        ".": {
+                                               OrigGroup: "group",
                                                Path:      ".",
                                                Mode:      fs.ModeDir | 0700,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger .",
                                                },
                                        },
                                        "dir": {
+                                               OrigGroup: "group",
                                                Path:      "dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir",
                                                },
                                        },
                                        "dir/file": {
+                                               OrigGroup: "group",
                                                Path:      "dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("content\n"),
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger dir/file",
                                                },
@@ -752,31 +740,31 @@ func TestSyncFiles(t *testing.T) {
                        safcm.MsgSyncReq{
                                Files: map[string]*safcm.File{
                                        "/": {
+                                               OrigGroup: "group",
                                                Path:      "/",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       0,
                                                Gid:       0,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger /",
                                                },
                                        },
                                        "/tmp": {
+                                               OrigGroup: "group",
                                                Path:      "/tmp",
                                                Mode:      fs.ModeDir | 0777 | fs.ModeSticky,
                                                Uid:       0,
                                                Gid:       0,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger /tmp",
                                                },
                                        },
                                        tmpTestFilePath: {
+                                               OrigGroup: "group",
                                                Path:      tmpTestFilePath,
                                                Mode:      0600,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group",
                                                TriggerCommands: []string{
                                                        "echo trigger /tmp/file",
                                                },
@@ -887,7 +875,7 @@ func TestSyncFile(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       defer os.Chdir(cwd)
+       defer os.Chdir(cwd) //nolint:errcheck
 
        err = os.RemoveAll("testdata")
        if err != nil {
@@ -963,7 +951,7 @@ func TestSyncFile(t *testing.T) {
                                `4: files: "file" (group): will create`,
                                `3: files: "file" (group): creating`,
                                `4: files: "file" (group): creating temporary file ".file*"`,
-                               `4: files: "file" (group): renaming "./.fileRND"`,
+                               `4: files: "file" (group): renaming ".fileRND"`,
                        },
                        nil,
                },
@@ -1006,6 +994,44 @@ func TestSyncFile(t *testing.T) {
                        nil,
                },
 
+               {
+                       "file: create, missing parent (dry-run)",
+                       safcm.MsgSyncReq{
+                               DryRun: true,
+                       },
+                       &safcm.File{
+                               Path:      "does-not-exist/file",
+                               Mode:      0644,
+                               Uid:       -1,
+                               Gid:       -1,
+                               Data:      []byte("content\n"),
+                               OrigGroup: "group",
+                       },
+                       nil,
+                       true,
+                       []ft.File{root},
+                       safcm.MsgSyncResp{
+                               FileChanges: []safcm.FileChange{
+                                       {
+                                               Path:    "does-not-exist/file",
+                                               Created: true,
+                                               New: safcm.FileChangeInfo{
+                                                       Mode:  0644,
+                                                       User:  user,
+                                                       Uid:   uid,
+                                                       Group: group,
+                                                       Gid:   gid,
+                                               },
+                                       },
+                               },
+                       },
+                       []string{
+                               `4: files: "does-not-exist/file" (group): will create (parent missing)`,
+                               `4: files: "does-not-exist/file" (group): dry-run, skipping changes`,
+                       },
+                       nil,
+               },
+
                {
                        "file: unchanged",
                        safcm.MsgSyncReq{},
@@ -1116,7 +1142,7 @@ func TestSyncFile(t *testing.T) {
                                `4: files: "file" (group): permission differs -rwxr-xr-x -> urwxr-xr-x`,
                                `3: files: "file" (group): updating`,
                                `4: files: "file" (group): creating temporary file ".file*"`,
-                               `4: files: "file" (group): renaming "./.fileRND"`,
+                               `4: files: "file" (group): renaming ".fileRND"`,
                        },
                        nil,
                },
@@ -1174,7 +1200,7 @@ func TestSyncFile(t *testing.T) {
                                `4: files: "file" (group): content differs`,
                                `3: files: "file" (group): updating`,
                                `4: files: "file" (group): creating temporary file ".file*"`,
-                               `4: files: "file" (group): renaming "./.fileRND"`,
+                               `4: files: "file" (group): renaming ".fileRND"`,
                        },
                        nil,
                },
@@ -1486,6 +1512,43 @@ func TestSyncFile(t *testing.T) {
                        nil,
                },
 
+               {
+                       "directory: create, missing parent (dry-run)",
+                       safcm.MsgSyncReq{
+                               DryRun: true,
+                       },
+                       &safcm.File{
+                               Path:      "does-not-exist/dir",
+                               Mode:      fs.ModeDir | 0755,
+                               Uid:       -1,
+                               Gid:       -1,
+                               OrigGroup: "group",
+                       },
+                       nil,
+                       true,
+                       []ft.File{root},
+                       safcm.MsgSyncResp{
+                               FileChanges: []safcm.FileChange{
+                                       {
+                                               Path:    "does-not-exist/dir",
+                                               Created: true,
+                                               New: safcm.FileChangeInfo{
+                                                       Mode:  fs.ModeDir | 0755,
+                                                       User:  user,
+                                                       Uid:   uid,
+                                                       Group: group,
+                                                       Gid:   gid,
+                                               },
+                                       },
+                               },
+                       },
+                       []string{
+                               `4: files: "does-not-exist/dir" (group): will create (parent missing)`,
+                               `4: files: "does-not-exist/dir" (group): dry-run, skipping changes`,
+                       },
+                       nil,
+               },
+
                {
                        "directory: unchanged",
                        safcm.MsgSyncReq{},
@@ -1734,7 +1797,7 @@ func TestSyncFile(t *testing.T) {
                                `4: files: "path" (group): type differs L--------- -> ----------`,
                                `3: files: "path" (group): updating`,
                                `4: files: "path" (group): creating temporary file ".path*"`,
-                               `4: files: "path" (group): renaming "./.pathRND"`,
+                               `4: files: "path" (group): renaming ".pathRND"`,
                        },
                        nil,
                },
@@ -1845,10 +1908,66 @@ func TestSyncFile(t *testing.T) {
                                `3: files: "path" (group): updating`,
                                `4: files: "path" (group): removing (due to type change)`,
                                `4: files: "path" (group): creating temporary file ".path*"`,
-                               `4: files: "path" (group): renaming "./.pathRND"`,
+                               `4: files: "path" (group): renaming ".pathRND"`,
                        },
                        nil,
                },
+               {
+                       "change: directory to file (non-empty)",
+                       safcm.MsgSyncReq{},
+                       &safcm.File{
+                               Path:      "path",
+                               Mode:      0666,
+                               Uid:       -1,
+                               Gid:       -1,
+                               OrigGroup: "group",
+                               Data:      []byte("content\n"),
+                       },
+                       func() {
+                               ft.CreateDirectory("path", 0777)
+                               ft.CreateFile("path/file", "content\n", 0644)
+                       },
+                       true,
+                       []ft.File{
+                               root,
+                               {
+                                       Path: "path",
+                                       Mode: fs.ModeDir | 0777,
+                               },
+                               {
+                                       Path: "path/file",
+                                       Mode: 0644,
+                                       Data: []byte("content\n"),
+                               },
+                       },
+                       safcm.MsgSyncResp{
+                               FileChanges: []safcm.FileChange{
+                                       {
+                                               Path: "path",
+                                               Old: safcm.FileChangeInfo{
+                                                       Mode:  fs.ModeDir | 0777,
+                                                       User:  user,
+                                                       Uid:   uid,
+                                                       Group: group,
+                                                       Gid:   gid,
+                                               },
+                                               New: safcm.FileChangeInfo{
+                                                       Mode:  0666,
+                                                       User:  user,
+                                                       Uid:   uid,
+                                                       Group: group,
+                                                       Gid:   gid,
+                                               },
+                                       },
+                               },
+                       },
+                       []string{
+                               `4: files: "path" (group): type differs d--------- -> ----------`,
+                               `3: files: "path" (group): updating`,
+                               `4: files: "path" (group): removing (due to type change)`,
+                       },
+                       fmt.Errorf("will not replace non-empty directory, please remove manually"),
+               },
 
                {
                        "change: directory to symlink",
@@ -1952,7 +2071,7 @@ func TestSyncFile(t *testing.T) {
                                `4: files: "path" (group): type differs p--------- -> ----------`,
                                `3: files: "path" (group): updating`,
                                `4: files: "path" (group): creating temporary file ".path*"`,
-                               `4: files: "path" (group): renaming "./.pathRND"`,
+                               `4: files: "path" (group): renaming ".pathRND"`,
                        },
                        nil,
                },
@@ -2116,6 +2235,94 @@ func TestSyncFile(t *testing.T) {
                        nil,
                },
 
+               // Symlink "attacks"
+
+               {
+                       "symlink in earlier path component",
+                       safcm.MsgSyncReq{},
+                       &safcm.File{
+                               Path:      "dir/file",
+                               Mode:      0644,
+                               Uid:       -1,
+                               Gid:       -1,
+                               OrigGroup: "group",
+                               Data:      []byte("content"),
+                       },
+                       func() {
+                               ft.CreateDirectory("tmp", 0755)
+                               ft.CreateSymlink("dir", "tmp")
+                       },
+                       false,
+                       []ft.File{
+                               root,
+                               {
+                                       Path: "dir",
+                                       Mode: fs.ModeSymlink | 0777,
+                                       Data: []byte("tmp"),
+                               },
+                               {
+                                       Path: "tmp",
+                                       Mode: fs.ModeDir | 0755,
+                               },
+                       },
+                       safcm.MsgSyncResp{},
+                       nil,
+                       fmt.Errorf("symlink not permitted in path: \"dir\""),
+               },
+
+               // Border cases
+
+               {
+                       "relative path with leading dot",
+                       safcm.MsgSyncReq{},
+                       &safcm.File{
+                               Path:      "./dir/file",
+                               Mode:      0644,
+                               Uid:       -1,
+                               Gid:       -1,
+                               OrigGroup: "group",
+                               Data:      []byte("content"),
+                       },
+                       func() {
+                               ft.CreateDirectory("dir", 0755)
+                       },
+                       true,
+                       []ft.File{
+                               root,
+                               {
+                                       Path: "dir",
+                                       Mode: fs.ModeDir | 0755,
+                               },
+                               {
+                                       Path: "dir/file",
+                                       Mode: 0644,
+                                       Data: []byte("content"),
+                               },
+                       },
+                       safcm.MsgSyncResp{
+                               FileChanges: []safcm.FileChange{
+                                       {
+                                               Path:    "./dir/file",
+                                               Created: true,
+                                               New: safcm.FileChangeInfo{
+                                                       Mode:  0644,
+                                                       User:  user,
+                                                       Uid:   uid,
+                                                       Group: group,
+                                                       Gid:   gid,
+                                               },
+                                       },
+                               },
+                       },
+                       []string{
+                               `4: files: "./dir/file" (group): will create`,
+                               `3: files: "./dir/file" (group): creating`,
+                               `4: files: "./dir/file" (group): creating temporary file "dir/.file*"`,
+                               `4: files: "./dir/file" (group): renaming "dir/.fileRND"`,
+                       },
+                       nil,
+               },
+
                // Diffs
 
                {