go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/connection/tar_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package connection_test 5 6 import ( 7 "io" 8 "net/http" 9 "os" 10 "regexp" 11 "testing" 12 13 "github.com/google/go-containerregistry/pkg/authn" 14 "github.com/google/go-containerregistry/pkg/name" 15 "github.com/google/go-containerregistry/pkg/v1/remote" 16 "github.com/google/go-containerregistry/pkg/v1/tarball" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 "go.mondoo.com/cnquery/providers-sdk/v1/inventory" 20 "go.mondoo.com/cnquery/providers/os/connection" 21 "go.mondoo.com/cnquery/providers/os/connection/tar" 22 ) 23 24 const ( 25 alpineImage = "alpine:3.9" 26 alpineContainerPath = "./alpine-container.tar" 27 28 centosImage = "centos:7" 29 centosContainerPath = "./centos-container.tar" 30 ) 31 32 func TestTarCommand(t *testing.T) { 33 err := cacheAlpine() 34 require.NoError(t, err, "should create tar without error") 35 36 c, err := connection.NewTarConnection(0, &inventory.Config{ 37 Type: "tar", 38 Options: map[string]string{ 39 connection.OPTION_FILE: alpineContainerPath, 40 }, 41 }, nil) 42 assert.Equal(t, nil, err, "should create tar without error") 43 44 cmd, err := c.RunCommand("ls /") 45 assert.Nil(t, err) 46 if assert.NotNil(t, cmd) { 47 assert.Equal(t, nil, err, "should execute without error") 48 assert.Equal(t, -1, cmd.ExitStatus, "command should not be executed") 49 stdoutContent, _ := io.ReadAll(cmd.Stdout) 50 assert.Equal(t, "", string(stdoutContent), "output should be correct") 51 stderrContent, _ := io.ReadAll(cmd.Stdout) 52 assert.Equal(t, "", string(stderrContent), "output should be correct") 53 } 54 } 55 56 func TestPlatformIdentifier(t *testing.T) { 57 err := cacheAlpine() 58 require.NoError(t, err, "should create tar without error") 59 60 conn, err := connection.NewTarConnection(0, &inventory.Config{ 61 Type: "tar", 62 Options: map[string]string{ 63 connection.OPTION_FILE: alpineContainerPath, 64 }, 65 }, nil) 66 require.NoError(t, err) 67 platformId, err := conn.Identifier() 68 require.NoError(t, err) 69 assert.True(t, len(platformId) > 0) 70 } 71 72 func TestTarSymlinkFile(t *testing.T) { 73 err := cacheAlpine() 74 require.NoError(t, err, "should create tar without error") 75 76 c, err := connection.NewTarConnection(0, &inventory.Config{ 77 Type: "tar", 78 Options: map[string]string{ 79 connection.OPTION_FILE: alpineContainerPath, 80 }, 81 }, nil) 82 assert.Equal(t, nil, err, "should create tar without error") 83 84 f, err := c.FileSystem().Open("/bin/cat") 85 assert.Nil(t, err) 86 if assert.NotNil(t, f) { 87 assert.Equal(t, nil, err, "should execute without error") 88 89 p := f.Name() 90 assert.Equal(t, "/bin/cat", p, "path should be correct") 91 92 stat, err := f.Stat() 93 assert.Equal(t, nil, err, "should stat without error") 94 assert.Equal(t, int64(796240), stat.Size(), "should read file size") 95 96 content, err := io.ReadAll(f) 97 assert.Equal(t, nil, err, "should execute without error") 98 assert.Equal(t, 796240, len(content), "should read the full content") 99 } 100 } 101 102 // deactivate test for now for speedier testing 103 // in contrast to alpine, the symlink on centos is pointing to a relative target and not an absolute one 104 func TestTarRelativeSymlinkFileCentos(t *testing.T) { 105 err := cacheCentos() 106 require.NoError(t, err, "should create tar without error") 107 108 c, err := connection.NewTarConnection(0, &inventory.Config{ 109 Type: "tar", 110 Options: map[string]string{ 111 connection.OPTION_FILE: centosContainerPath, 112 }, 113 }, nil) 114 assert.Equal(t, nil, err, "should create tar without error") 115 116 f, err := c.FileSystem().Open("/etc/redhat-release") 117 require.NoError(t, err) 118 119 if assert.NotNil(t, f) { 120 assert.Equal(t, nil, err, "should execute without error") 121 122 p := f.Name() 123 assert.Equal(t, "/etc/redhat-release", p, "path should be correct") 124 125 stat, err := f.Stat() 126 assert.Equal(t, nil, err, "should stat without error") 127 assert.Equal(t, int64(37), stat.Size(), "should read file size") 128 129 content, err := io.ReadAll(f) 130 assert.Equal(t, nil, err, "should execute without error") 131 assert.Equal(t, 37, len(content), "should read the full content") 132 } 133 } 134 135 func TestTarFile(t *testing.T) { 136 err := cacheAlpine() 137 require.NoError(t, err, "should create tar without error") 138 139 c, err := connection.NewTarConnection(0, &inventory.Config{ 140 Type: "tar", 141 Options: map[string]string{ 142 connection.OPTION_FILE: alpineContainerPath, 143 }, 144 }, nil) 145 assert.Equal(t, nil, err, "should create tar without error") 146 147 f, err := c.FileSystem().Open("/etc/alpine-release") 148 assert.Nil(t, err) 149 if assert.NotNil(t, f) { 150 assert.Equal(t, nil, err, "should execute without error") 151 152 p := f.Name() 153 assert.Equal(t, "/etc/alpine-release", p, "path should be correct") 154 155 stat, err := f.Stat() 156 assert.Equal(t, int64(6), stat.Size(), "should read file size") 157 assert.Equal(t, nil, err, "should execute without error") 158 159 content, err := io.ReadAll(f) 160 assert.Equal(t, nil, err, "should execute without error") 161 assert.Equal(t, 6, len(content), "should read the full content") 162 } 163 } 164 165 func TestFilePermissions(t *testing.T) { 166 err := cacheAlpine() 167 require.NoError(t, err, "should create tar without error") 168 169 c, err := connection.NewTarConnection(0, &inventory.Config{ 170 Type: "tar", 171 Options: map[string]string{ 172 connection.OPTION_FILE: alpineContainerPath, 173 }, 174 }, nil) 175 require.NoError(t, err) 176 177 path := "/etc/alpine-release" 178 details, err := c.FileInfo(path) 179 require.NoError(t, err) 180 assert.Equal(t, int64(0), details.Uid) 181 assert.Equal(t, int64(0), details.Gid) 182 assert.True(t, details.Size >= 0) 183 assert.Equal(t, false, details.Mode.IsDir()) 184 assert.Equal(t, true, details.Mode.IsRegular()) 185 assert.Equal(t, "-rw-r--r--", details.Mode.String()) 186 assert.True(t, details.Mode.UserReadable()) 187 assert.True(t, details.Mode.UserWriteable()) 188 assert.False(t, details.Mode.UserExecutable()) 189 assert.True(t, details.Mode.GroupReadable()) 190 assert.False(t, details.Mode.GroupWriteable()) 191 assert.False(t, details.Mode.GroupExecutable()) 192 assert.True(t, details.Mode.OtherReadable()) 193 assert.False(t, details.Mode.OtherWriteable()) 194 assert.False(t, details.Mode.OtherExecutable()) 195 assert.False(t, details.Mode.Suid()) 196 assert.False(t, details.Mode.Sgid()) 197 assert.False(t, details.Mode.Sticky()) 198 199 path = "/etc" 200 details, err = c.FileInfo(path) 201 require.NoError(t, err) 202 assert.Equal(t, int64(0), details.Uid) 203 assert.Equal(t, int64(0), details.Gid) 204 assert.True(t, details.Size >= 0) 205 assert.True(t, details.Mode.IsDir()) 206 assert.False(t, details.Mode.IsRegular()) 207 assert.Equal(t, "drwxr-xr-x", details.Mode.String()) 208 assert.True(t, details.Mode.UserReadable()) 209 assert.True(t, details.Mode.UserWriteable()) 210 assert.True(t, details.Mode.UserExecutable()) 211 assert.True(t, details.Mode.GroupReadable()) 212 assert.False(t, details.Mode.GroupWriteable()) 213 assert.True(t, details.Mode.GroupExecutable()) 214 assert.True(t, details.Mode.OtherReadable()) 215 assert.False(t, details.Mode.OtherWriteable()) 216 assert.True(t, details.Mode.OtherExecutable()) 217 assert.False(t, details.Mode.Suid()) 218 assert.False(t, details.Mode.Sgid()) 219 assert.False(t, details.Mode.Sticky()) 220 } 221 222 func TestTarFileFind(t *testing.T) { 223 err := cacheAlpine() 224 require.NoError(t, err, "should create tar without error") 225 226 c, err := connection.NewTarConnection(0, &inventory.Config{ 227 Type: "tar", 228 Options: map[string]string{ 229 connection.OPTION_FILE: alpineContainerPath, 230 }, 231 }, nil) 232 assert.Equal(t, nil, err, "should create tar without error") 233 234 fs := c.FileSystem() 235 236 fSearch := fs.(*tar.FS) 237 238 infos, err := fSearch.Find("/", regexp.MustCompile(`alpine-release`), "file") 239 require.NoError(t, err) 240 241 assert.Equal(t, 1, len(infos)) 242 } 243 244 func cacheAlpine() error { 245 return cacheImageToTar(alpineImage, alpineContainerPath) 246 } 247 248 func cacheCentos() error { 249 return cacheImageToTar(centosImage, centosContainerPath) 250 } 251 252 func cacheImageToTar(source string, filename string) error { 253 // check if the cache is already there 254 _, err := os.Stat(filename) 255 if err == nil { 256 return nil 257 } 258 259 tag, err := name.NewTag(source, name.WeakValidation) 260 if err != nil { 261 return err 262 } 263 264 auth, err := authn.DefaultKeychain.Resolve(tag.Registry) 265 if err != nil { 266 return err 267 } 268 269 img, err := remote.Image(tag, remote.WithAuth(auth), remote.WithTransport(http.DefaultTransport)) 270 if err != nil { 271 return err 272 } 273 274 return tarball.WriteToFile(filename, tag, img) 275 }