github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/internal/fileresolver/chroot_context_test.go (about) 1 package fileresolver 2 3 import ( 4 "os" 5 "path/filepath" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func Test_ChrootContext_RequestResponse(t *testing.T) { 13 // / 14 // somewhere/ 15 // outside.txt 16 // root-link -> ./ 17 // path/ 18 // to/ 19 // abs-inside.txt -> /path/to/the/file.txt # absolute link to somewhere inside of the root 20 // rel-inside.txt -> ./the/file.txt # relative link to somewhere inside of the root 21 // the/ 22 // file.txt 23 // abs-outside.txt -> /somewhere/outside.txt # absolute link to outside of the root 24 // rel-outside -> ../../../somewhere/outside.txt # relative link to outside of the root 25 // 26 27 testDir, err := os.Getwd() 28 require.NoError(t, err) 29 relative := filepath.Join("test-fixtures", "req-resp") 30 absolute := filepath.Join(testDir, relative) 31 32 absPathToTheFile := filepath.Join(absolute, "path", "to", "the", "file.txt") 33 34 absAbsInsidePath := filepath.Join(absolute, "path", "to", "abs-inside.txt") 35 absAbsOutsidePath := filepath.Join(absolute, "path", "to", "the", "abs-outside.txt") 36 37 absRelOutsidePath := filepath.Join(absolute, "path", "to", "the", "rel-outside.txt") 38 39 relViaLink := filepath.Join(relative, "root-link") 40 absViaLink := filepath.Join(absolute, "root-link") 41 42 absViaLinkPathToTheFile := filepath.Join(absViaLink, "path", "to", "the", "file.txt") 43 absViaLinkAbsOutsidePath := filepath.Join(absViaLink, "path", "to", "the", "abs-outside.txt") 44 absViaLinkRelOutsidePath := filepath.Join(absViaLink, "path", "to", "the", "rel-outside.txt") 45 46 relViaDoubleLink := filepath.Join(relative, "root-link", "root-link") 47 absViaDoubleLink := filepath.Join(absolute, "root-link", "root-link") 48 49 absViaDoubleLinkPathToTheFile := filepath.Join(absViaDoubleLink, "path", "to", "the", "file.txt") 50 absViaDoubleLinkRelOutsidePath := filepath.Join(absViaDoubleLink, "path", "to", "the", "rel-outside.txt") 51 52 cleanup := func() { 53 _ = os.Remove(absAbsInsidePath) 54 _ = os.Remove(absAbsOutsidePath) 55 } 56 57 // ensure the absolute symlinks are cleaned up from any previous runs 58 cleanup() 59 60 require.NoError(t, os.Symlink(filepath.Join(absolute, "path", "to", "the", "file.txt"), absAbsInsidePath)) 61 require.NoError(t, os.Symlink(filepath.Join(absolute, "somewhere", "outside.txt"), absAbsOutsidePath)) 62 63 t.Cleanup(cleanup) 64 65 cases := []struct { 66 name string 67 cwd string 68 root string 69 base string 70 input string 71 expectedNativePath string 72 expectedChrootPath string 73 }{ 74 { 75 name: "relative root, relative request, direct", 76 root: relative, 77 input: "path/to/the/file.txt", 78 expectedNativePath: absPathToTheFile, 79 expectedChrootPath: "path/to/the/file.txt", 80 }, 81 { 82 name: "abs root, relative request, direct", 83 root: absolute, 84 input: "path/to/the/file.txt", 85 expectedNativePath: absPathToTheFile, 86 expectedChrootPath: "path/to/the/file.txt", 87 }, 88 { 89 name: "relative root, abs request, direct", 90 root: relative, 91 input: "/path/to/the/file.txt", 92 expectedNativePath: absPathToTheFile, 93 expectedChrootPath: "path/to/the/file.txt", 94 }, 95 { 96 name: "abs root, abs request, direct", 97 root: absolute, 98 input: "/path/to/the/file.txt", 99 expectedNativePath: absPathToTheFile, 100 expectedChrootPath: "path/to/the/file.txt", 101 }, 102 // cwd within root... 103 { 104 name: "relative root, relative request, direct, cwd within root", 105 cwd: filepath.Join(relative, "path/to"), 106 root: "../../", 107 input: "path/to/the/file.txt", 108 expectedNativePath: absPathToTheFile, 109 expectedChrootPath: "path/to/the/file.txt", 110 }, 111 { 112 name: "abs root, relative request, direct, cwd within root", 113 cwd: filepath.Join(relative, "path/to"), 114 root: absolute, 115 input: "path/to/the/file.txt", 116 expectedNativePath: absPathToTheFile, 117 expectedChrootPath: "path/to/the/file.txt", 118 }, 119 { 120 name: "relative root, abs request, direct, cwd within root", 121 cwd: filepath.Join(relative, "path/to"), 122 root: "../../", 123 input: "/path/to/the/file.txt", 124 expectedNativePath: absPathToTheFile, 125 expectedChrootPath: "path/to/the/file.txt", 126 }, 127 { 128 name: "abs root, abs request, direct, cwd within root", 129 cwd: filepath.Join(relative, "path/to"), 130 131 root: absolute, 132 input: "/path/to/the/file.txt", 133 expectedNativePath: absPathToTheFile, 134 expectedChrootPath: "path/to/the/file.txt", 135 }, 136 // cwd within symlink root... 137 { 138 name: "relative root, relative request, direct, cwd within symlink root", 139 cwd: relViaLink, 140 root: "./", 141 input: "path/to/the/file.txt", 142 expectedNativePath: absViaLinkPathToTheFile, 143 expectedChrootPath: "path/to/the/file.txt", 144 }, 145 { 146 name: "abs root, relative request, direct, cwd within symlink root", 147 cwd: relViaLink, 148 root: absViaLink, 149 input: "path/to/the/file.txt", 150 expectedNativePath: absPathToTheFile, 151 expectedChrootPath: "path/to/the/file.txt", 152 }, 153 { 154 name: "relative root, abs request, direct, cwd within symlink root", 155 cwd: relViaLink, 156 root: "./", 157 input: "/path/to/the/file.txt", 158 expectedNativePath: absViaLinkPathToTheFile, 159 expectedChrootPath: "path/to/the/file.txt", 160 }, 161 { 162 name: "abs root, abs request, direct, cwd within symlink root", 163 cwd: relViaLink, 164 root: absViaLink, 165 input: "/path/to/the/file.txt", 166 expectedNativePath: absPathToTheFile, 167 expectedChrootPath: "path/to/the/file.txt", 168 }, 169 // cwd within symlink root, request nested within... 170 { 171 name: "relative root, relative nested request, direct, cwd within symlink root", 172 cwd: relViaLink, 173 root: "./path", 174 input: "to/the/file.txt", 175 expectedNativePath: absViaLinkPathToTheFile, 176 expectedChrootPath: "to/the/file.txt", 177 }, 178 { 179 name: "abs root, relative nested request, direct, cwd within symlink root", 180 cwd: relViaLink, 181 root: filepath.Join(absViaLink, "path"), 182 input: "to/the/file.txt", 183 expectedNativePath: absPathToTheFile, 184 expectedChrootPath: "to/the/file.txt", 185 }, 186 { 187 name: "relative root, abs nested request, direct, cwd within symlink root", 188 cwd: relViaLink, 189 root: "./path", 190 input: "/to/the/file.txt", 191 expectedNativePath: absViaLinkPathToTheFile, 192 expectedChrootPath: "to/the/file.txt", 193 }, 194 { 195 name: "abs root, abs nested request, direct, cwd within symlink root", 196 cwd: relViaLink, 197 root: filepath.Join(absViaLink, "path"), 198 input: "/to/the/file.txt", 199 expectedNativePath: absPathToTheFile, 200 expectedChrootPath: "to/the/file.txt", 201 }, 202 // cwd within DOUBLE symlink root... 203 { 204 name: "relative root, relative request, direct, cwd within (double) symlink root", 205 cwd: relViaDoubleLink, 206 root: "./", 207 input: "path/to/the/file.txt", 208 expectedNativePath: absViaDoubleLinkPathToTheFile, 209 expectedChrootPath: "path/to/the/file.txt", 210 }, 211 { 212 name: "abs root, relative request, direct, cwd within (double) symlink root", 213 cwd: relViaDoubleLink, 214 root: absViaDoubleLink, 215 input: "path/to/the/file.txt", 216 expectedNativePath: absPathToTheFile, 217 expectedChrootPath: "path/to/the/file.txt", 218 }, 219 { 220 name: "relative root, abs request, direct, cwd within (double) symlink root", 221 cwd: relViaDoubleLink, 222 root: "./", 223 input: "/path/to/the/file.txt", 224 expectedNativePath: absViaDoubleLinkPathToTheFile, 225 expectedChrootPath: "path/to/the/file.txt", 226 }, 227 { 228 name: "abs root, abs request, direct, cwd within (double) symlink root", 229 cwd: relViaDoubleLink, 230 root: absViaDoubleLink, 231 input: "/path/to/the/file.txt", 232 expectedNativePath: absPathToTheFile, 233 expectedChrootPath: "path/to/the/file.txt", 234 }, 235 // cwd within DOUBLE symlink root, request nested within... 236 { 237 name: "relative root, relative nested request, direct, cwd within (double) symlink root", 238 cwd: relViaDoubleLink, 239 root: "./path", 240 input: "to/the/file.txt", 241 expectedNativePath: absViaDoubleLinkPathToTheFile, 242 expectedChrootPath: "to/the/file.txt", 243 }, 244 { 245 name: "abs root, relative nested request, direct, cwd within (double) symlink root", 246 cwd: relViaDoubleLink, 247 root: filepath.Join(absViaDoubleLink, "path"), 248 input: "to/the/file.txt", 249 expectedNativePath: absPathToTheFile, 250 expectedChrootPath: "to/the/file.txt", 251 }, 252 { 253 name: "relative root, abs nested request, direct, cwd within (double) symlink root", 254 cwd: relViaDoubleLink, 255 root: "./path", 256 input: "/to/the/file.txt", 257 expectedNativePath: absViaDoubleLinkPathToTheFile, 258 expectedChrootPath: "to/the/file.txt", 259 }, 260 { 261 name: "abs root, abs nested request, direct, cwd within (double) symlink root", 262 cwd: relViaDoubleLink, 263 root: filepath.Join(absViaDoubleLink, "path"), 264 input: "/to/the/file.txt", 265 expectedNativePath: absPathToTheFile, 266 expectedChrootPath: "to/the/file.txt", 267 }, 268 // cwd within DOUBLE symlink root, request nested DEEP within... 269 { 270 name: "relative root, relative nested request, direct, cwd deep within (double) symlink root", 271 cwd: filepath.Join(relViaDoubleLink, "path", "to"), 272 root: "../", 273 input: "to/the/file.txt", 274 expectedNativePath: absViaDoubleLinkPathToTheFile, 275 expectedChrootPath: "to/the/file.txt", 276 }, 277 { 278 name: "abs root, relative nested request, direct, cwd deep within (double) symlink root", 279 cwd: filepath.Join(relViaDoubleLink, "path", "to"), 280 root: filepath.Join(absViaDoubleLink, "path"), 281 input: "to/the/file.txt", 282 expectedNativePath: absPathToTheFile, 283 expectedChrootPath: "to/the/file.txt", 284 }, 285 { 286 name: "relative root, abs nested request, direct, cwd deep within (double) symlink root", 287 cwd: filepath.Join(relViaDoubleLink, "path", "to"), 288 root: "../", 289 input: "/to/the/file.txt", 290 expectedNativePath: absViaDoubleLinkPathToTheFile, 291 expectedChrootPath: "to/the/file.txt", 292 }, 293 { 294 name: "abs root, abs nested request, direct, cwd deep within (double) symlink root", 295 cwd: filepath.Join(relViaDoubleLink, "path", "to"), 296 root: filepath.Join(absViaDoubleLink, "path"), 297 input: "/to/the/file.txt", 298 expectedNativePath: absPathToTheFile, 299 expectedChrootPath: "to/the/file.txt", 300 }, 301 // link to outside of root cases... 302 { 303 name: "relative root, relative request, abs indirect (outside of root)", 304 root: filepath.Join(relative, "path"), 305 input: "to/the/abs-outside.txt", 306 expectedNativePath: absAbsOutsidePath, 307 expectedChrootPath: "to/the/abs-outside.txt", 308 }, 309 { 310 name: "abs root, relative request, abs indirect (outside of root)", 311 root: filepath.Join(absolute, "path"), 312 input: "to/the/abs-outside.txt", 313 expectedNativePath: absAbsOutsidePath, 314 expectedChrootPath: "to/the/abs-outside.txt", 315 }, 316 { 317 name: "relative root, abs request, abs indirect (outside of root)", 318 root: filepath.Join(relative, "path"), 319 input: "/to/the/abs-outside.txt", 320 expectedNativePath: absAbsOutsidePath, 321 expectedChrootPath: "to/the/abs-outside.txt", 322 }, 323 { 324 name: "abs root, abs request, abs indirect (outside of root)", 325 root: filepath.Join(absolute, "path"), 326 input: "/to/the/abs-outside.txt", 327 expectedNativePath: absAbsOutsidePath, 328 expectedChrootPath: "to/the/abs-outside.txt", 329 }, 330 { 331 name: "relative root, relative request, relative indirect (outside of root)", 332 root: filepath.Join(relative, "path"), 333 input: "to/the/rel-outside.txt", 334 expectedNativePath: absRelOutsidePath, 335 expectedChrootPath: "to/the/rel-outside.txt", 336 }, 337 { 338 name: "abs root, relative request, relative indirect (outside of root)", 339 root: filepath.Join(absolute, "path"), 340 input: "to/the/rel-outside.txt", 341 expectedNativePath: absRelOutsidePath, 342 expectedChrootPath: "to/the/rel-outside.txt", 343 }, 344 { 345 name: "relative root, abs request, relative indirect (outside of root)", 346 root: filepath.Join(relative, "path"), 347 input: "/to/the/rel-outside.txt", 348 expectedNativePath: absRelOutsidePath, 349 expectedChrootPath: "to/the/rel-outside.txt", 350 }, 351 { 352 name: "abs root, abs request, relative indirect (outside of root)", 353 root: filepath.Join(absolute, "path"), 354 input: "/to/the/rel-outside.txt", 355 expectedNativePath: absRelOutsidePath, 356 expectedChrootPath: "to/the/rel-outside.txt", 357 }, 358 // link to outside of root cases... cwd within symlink root 359 { 360 name: "relative root, relative request, abs indirect (outside of root), cwd within symlink root", 361 cwd: relViaLink, 362 root: "path", 363 input: "to/the/abs-outside.txt", 364 expectedNativePath: absViaLinkAbsOutsidePath, 365 expectedChrootPath: "to/the/abs-outside.txt", 366 }, 367 { 368 name: "abs root, relative request, abs indirect (outside of root), cwd within symlink root", 369 cwd: relViaLink, 370 root: filepath.Join(absolute, "path"), 371 input: "to/the/abs-outside.txt", 372 expectedNativePath: absAbsOutsidePath, 373 expectedChrootPath: "to/the/abs-outside.txt", 374 }, 375 { 376 name: "relative root, abs request, abs indirect (outside of root), cwd within symlink root", 377 cwd: relViaLink, 378 root: "path", 379 input: "/to/the/abs-outside.txt", 380 expectedNativePath: absViaLinkAbsOutsidePath, 381 expectedChrootPath: "to/the/abs-outside.txt", 382 }, 383 { 384 name: "abs root, abs request, abs indirect (outside of root), cwd within symlink root", 385 cwd: relViaLink, 386 root: filepath.Join(absolute, "path"), 387 input: "/to/the/abs-outside.txt", 388 expectedNativePath: absAbsOutsidePath, 389 expectedChrootPath: "to/the/abs-outside.txt", 390 }, 391 { 392 name: "relative root, relative request, relative indirect (outside of root), cwd within symlink root", 393 cwd: relViaLink, 394 root: "path", 395 input: "to/the/rel-outside.txt", 396 expectedNativePath: absViaLinkRelOutsidePath, 397 expectedChrootPath: "to/the/rel-outside.txt", 398 }, 399 { 400 name: "abs root, relative request, relative indirect (outside of root), cwd within symlink root", 401 cwd: relViaLink, 402 root: filepath.Join(absolute, "path"), 403 input: "to/the/rel-outside.txt", 404 expectedNativePath: absRelOutsidePath, 405 expectedChrootPath: "to/the/rel-outside.txt", 406 }, 407 { 408 name: "relative root, abs request, relative indirect (outside of root), cwd within symlink root", 409 cwd: relViaLink, 410 root: "path", 411 input: "/to/the/rel-outside.txt", 412 expectedNativePath: absViaLinkRelOutsidePath, 413 expectedChrootPath: "to/the/rel-outside.txt", 414 }, 415 { 416 name: "abs root, abs request, relative indirect (outside of root), cwd within symlink root", 417 cwd: relViaLink, 418 root: filepath.Join(absolute, "path"), 419 input: "/to/the/rel-outside.txt", 420 expectedNativePath: absRelOutsidePath, 421 expectedChrootPath: "to/the/rel-outside.txt", 422 }, 423 { 424 name: "relative root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root", 425 cwd: relViaDoubleLink, 426 root: "path", 427 input: "to/the/rel-outside.txt", 428 expectedNativePath: absViaDoubleLinkRelOutsidePath, 429 expectedChrootPath: "to/the/rel-outside.txt", 430 }, 431 { 432 name: "abs root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root", 433 cwd: relViaDoubleLink, 434 root: filepath.Join(absolute, "path"), 435 input: "to/the/rel-outside.txt", 436 expectedNativePath: absRelOutsidePath, 437 expectedChrootPath: "to/the/rel-outside.txt", 438 }, 439 { 440 name: "relative root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root", 441 cwd: relViaDoubleLink, 442 root: "path", 443 input: "/to/the/rel-outside.txt", 444 expectedNativePath: absViaDoubleLinkRelOutsidePath, 445 expectedChrootPath: "to/the/rel-outside.txt", 446 }, 447 { 448 name: "abs root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root", 449 cwd: relViaDoubleLink, 450 root: filepath.Join(absolute, "path"), 451 input: "/to/the/rel-outside.txt", 452 expectedNativePath: absRelOutsidePath, 453 expectedChrootPath: "to/the/rel-outside.txt", 454 }, 455 } 456 for _, c := range cases { 457 t.Run(c.name, func(t *testing.T) { 458 459 // we need to mimic a shell, otherwise we won't get a path within a symlink 460 targetPath := filepath.Join(testDir, c.cwd) 461 t.Setenv("PWD", filepath.Clean(targetPath)) 462 463 require.NoError(t, err) 464 require.NoError(t, os.Chdir(targetPath)) 465 t.Cleanup(func() { 466 require.NoError(t, os.Chdir(testDir)) 467 }) 468 469 chroot, err := NewChrootContextFromCWD(c.root, c.base) 470 require.NoError(t, err) 471 require.NotNil(t, chroot) 472 473 req, err := chroot.ToNativePath(c.input) 474 require.NoError(t, err) 475 assert.Equal(t, c.expectedNativePath, req, "native path different") 476 477 resp := chroot.ToChrootPath(req) 478 assert.Equal(t, c.expectedChrootPath, resp, "chroot path different") 479 }) 480 } 481 }