skipped 22 lines 23 23 "github.com/anchore/syft/syft/file" 24 24 ) 25 25 26 + func Test_UnindexDirectoryResolver_RequestRelativePathWithinSymlink(t *testing.T) { 27 + pwd, err := os.Getwd() 28 + 29 + // we need to mimic a shell, otherwise we won't get a path within a symlink 30 + targetPath := filepath.Join(pwd, "./test-fixtures/symlinked-root/nested/link-root/nested") 31 + t.Setenv("PWD", targetPath) 32 + 33 + require.NoError(t, err) 34 + require.NoError(t, os.Chdir(targetPath)) 35 + t.Cleanup(func() { 36 + require.NoError(t, os.Chdir(pwd)) 37 + }) 38 + 39 + resolver := NewFromUnindexedDirectory("./") 40 + require.NoError(t, err) 41 + 42 + locations, err := resolver.FilesByPath("file2.txt") 43 + require.NoError(t, err) 44 + require.Len(t, locations, 1) 45 + 46 + // TODO: this is technically not correct behavior since this is reporting the symlink path (virtual path) and 47 + // not the real path. 48 + require.False(t, filepath.IsAbs(locations[0].RealPath), "should be relative path") 49 + } 50 + 51 + func Test_UnindexDirectoryResolver_FilesByPath_request_response(t *testing.T) { 52 + // / 53 + // somewhere/ 54 + // outside.txt 55 + // root-link -> ./ 56 + // path/ 57 + // to/ 58 + // abs-inside.txt -> /path/to/the/file.txt # absolute link to somewhere inside of the root 59 + // rel-inside.txt -> ./the/file.txt # relative link to somewhere inside of the root 60 + // the/ 61 + // file.txt 62 + // abs-outside.txt -> /somewhere/outside.txt # absolute link to outside of the root 63 + // rel-outside -> ../../../somewhere/outside.txt # relative link to outside of the root 64 + // 65 + 66 + testDir, err := os.Getwd() 67 + require.NoError(t, err) 68 + relative := filepath.Join("test-fixtures", "req-resp") 69 + absolute := filepath.Join(testDir, relative) 70 + 71 + absInsidePath := filepath.Join(absolute, "path", "to", "abs-inside.txt") 72 + absOutsidePath := filepath.Join(absolute, "path", "to", "the", "abs-outside.txt") 73 + 74 + relativeViaLink := filepath.Join(relative, "root-link") 75 + absoluteViaLink := filepath.Join(absolute, "root-link") 76 + 77 + relativeViaDoubleLink := filepath.Join(relative, "root-link", "root-link") 78 + absoluteViaDoubleLink := filepath.Join(absolute, "root-link", "root-link") 79 + 80 + cleanup := func() { 81 + _ = os.Remove(absInsidePath) 82 + _ = os.Remove(absOutsidePath) 83 + } 84 + 85 + // ensure the absolute symlinks are cleaned up from any previous runs 86 + cleanup() 87 + 88 + require.NoError(t, os.Symlink(filepath.Join(absolute, "path", "to", "the", "file.txt"), absInsidePath)) 89 + require.NoError(t, os.Symlink(filepath.Join(absolute, "somewhere", "outside.txt"), absOutsidePath)) 90 + 91 + t.Cleanup(cleanup) 92 + 93 + cases := []struct { 94 + name string 95 + cwd string 96 + root string 97 + base string 98 + input string 99 + expectedRealPath string 100 + expectedVirtualPath string 101 + }{ 102 + { 103 + name: "relative root, relative request, direct", 104 + root: relative, 105 + input: "path/to/the/file.txt", 106 + expectedRealPath: "path/to/the/file.txt", 107 + }, 108 + { 109 + name: "abs root, relative request, direct", 110 + root: absolute, 111 + input: "path/to/the/file.txt", 112 + expectedRealPath: "path/to/the/file.txt", 113 + }, 114 + { 115 + name: "relative root, abs request, direct", 116 + root: relative, 117 + input: "/path/to/the/file.txt", 118 + expectedRealPath: "path/to/the/file.txt", 119 + }, 120 + { 121 + name: "abs root, abs request, direct", 122 + root: absolute, 123 + input: "/path/to/the/file.txt", 124 + expectedRealPath: "path/to/the/file.txt", 125 + }, 126 + // cwd within root... 127 + { 128 + name: "relative root, relative request, direct, cwd within root", 129 + cwd: filepath.Join(relative, "path/to"), 130 + root: "../../", 131 + input: "path/to/the/file.txt", 132 + expectedRealPath: "path/to/the/file.txt", 133 + }, 134 + { 135 + name: "abs root, relative request, direct, cwd within root", 136 + cwd: filepath.Join(relative, "path/to"), 137 + root: absolute, 138 + input: "path/to/the/file.txt", 139 + expectedRealPath: "path/to/the/file.txt", 140 + }, 141 + { 142 + name: "relative root, abs request, direct, cwd within root", 143 + cwd: filepath.Join(relative, "path/to"), 144 + root: "../../", 145 + input: "/path/to/the/file.txt", 146 + expectedRealPath: "path/to/the/file.txt", 147 + }, 148 + { 149 + name: "abs root, abs request, direct, cwd within root", 150 + cwd: filepath.Join(relative, "path/to"), 151 + 152 + root: absolute, 153 + input: "/path/to/the/file.txt", 154 + expectedRealPath: "path/to/the/file.txt", 155 + }, 156 + // cwd within symlink root... 157 + { 158 + name: "relative root, relative request, direct, cwd within symlink root", 159 + cwd: relativeViaLink, 160 + root: "./", 161 + input: "path/to/the/file.txt", 162 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 163 + // in this case for the unindexed resolver, which is not correct. 164 + expectedRealPath: "path/to/the/file.txt", 165 + }, 166 + { 167 + name: "abs root, relative request, direct, cwd within symlink root", 168 + cwd: relativeViaLink, 169 + root: absoluteViaLink, 170 + input: "path/to/the/file.txt", 171 + expectedRealPath: "path/to/the/file.txt", 172 + }, 173 + { 174 + name: "relative root, abs request, direct, cwd within symlink root", 175 + cwd: relativeViaLink, 176 + root: "./", 177 + input: "/path/to/the/file.txt", 178 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 179 + // in this case for the unindexed resolver, which is not correct. 180 + expectedRealPath: "path/to/the/file.txt", 181 + }, 182 + { 183 + name: "abs root, abs request, direct, cwd within symlink root", 184 + cwd: relativeViaLink, 185 + root: absoluteViaLink, 186 + input: "/path/to/the/file.txt", 187 + expectedRealPath: "path/to/the/file.txt", 188 + }, 189 + // cwd within symlink root, request nested within... 190 + { 191 + name: "relative root, relative nested request, direct, cwd within symlink root", 192 + cwd: relativeViaLink, 193 + root: "./path", 194 + input: "to/the/file.txt", 195 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 196 + // in this case for the unindexed resolver, which is not correct. 197 + expectedRealPath: "to/the/file.txt", 198 + }, 199 + { 200 + name: "abs root, relative nested request, direct, cwd within symlink root", 201 + cwd: relativeViaLink, 202 + root: filepath.Join(absoluteViaLink, "path"), 203 + input: "to/the/file.txt", 204 + expectedRealPath: "to/the/file.txt", 205 + }, 206 + { 207 + name: "relative root, abs nested request, direct, cwd within symlink root", 208 + cwd: relativeViaLink, 209 + root: "./path", 210 + input: "/to/the/file.txt", 211 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 212 + // in this case for the unindexed resolver, which is not correct. 213 + expectedRealPath: "to/the/file.txt", 214 + }, 215 + { 216 + name: "abs root, abs nested request, direct, cwd within symlink root", 217 + cwd: relativeViaLink, 218 + root: filepath.Join(absoluteViaLink, "path"), 219 + input: "/to/the/file.txt", 220 + expectedRealPath: "to/the/file.txt", 221 + }, 222 + // cwd within DOUBLE symlink root... 223 + { 224 + name: "relative root, relative request, direct, cwd within (double) symlink root", 225 + cwd: relativeViaDoubleLink, 226 + root: "./", 227 + input: "path/to/the/file.txt", 228 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 229 + // in this case for the unindexed resolver, which is not correct. 230 + expectedRealPath: "path/to/the/file.txt", 231 + }, 232 + { 233 + name: "abs root, relative request, direct, cwd within (double) symlink root", 234 + cwd: relativeViaDoubleLink, 235 + root: absoluteViaDoubleLink, 236 + input: "path/to/the/file.txt", 237 + expectedRealPath: "path/to/the/file.txt", 238 + }, 239 + { 240 + name: "relative root, abs request, direct, cwd within (double) symlink root", 241 + cwd: relativeViaDoubleLink, 242 + root: "./", 243 + input: "/path/to/the/file.txt", 244 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 245 + // in this case for the unindexed resolver, which is not correct. 246 + expectedRealPath: "path/to/the/file.txt", 247 + }, 248 + { 249 + name: "abs root, abs request, direct, cwd within (double) symlink root", 250 + cwd: relativeViaDoubleLink, 251 + root: absoluteViaDoubleLink, 252 + input: "/path/to/the/file.txt", 253 + expectedRealPath: "path/to/the/file.txt", 254 + }, 255 + // cwd within DOUBLE symlink root, request nested within... 256 + { 257 + name: "relative root, relative nested request, direct, cwd within (double) symlink root", 258 + cwd: relativeViaDoubleLink, 259 + root: "./path", 260 + input: "to/the/file.txt", 261 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 262 + // in this case for the unindexed resolver, which is not correct. 263 + expectedRealPath: "to/the/file.txt", 264 + }, 265 + { 266 + name: "abs root, relative nested request, direct, cwd within (double) symlink root", 267 + cwd: relativeViaDoubleLink, 268 + root: filepath.Join(absoluteViaDoubleLink, "path"), 269 + input: "to/the/file.txt", 270 + expectedRealPath: "to/the/file.txt", 271 + }, 272 + { 273 + name: "relative root, abs nested request, direct, cwd within (double) symlink root", 274 + cwd: relativeViaDoubleLink, 275 + root: "./path", 276 + input: "/to/the/file.txt", 277 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 278 + // in this case for the unindexed resolver, which is not correct. 279 + expectedRealPath: "to/the/file.txt", 280 + }, 281 + { 282 + name: "abs root, abs nested request, direct, cwd within (double) symlink root", 283 + cwd: relativeViaDoubleLink, 284 + root: filepath.Join(absoluteViaDoubleLink, "path"), 285 + input: "/to/the/file.txt", 286 + expectedRealPath: "to/the/file.txt", 287 + }, 288 + // cwd within DOUBLE symlink root, request nested DEEP within... 289 + { 290 + name: "relative root, relative nested request, direct, cwd deep within (double) symlink root", 291 + cwd: filepath.Join(relativeViaDoubleLink, "path", "to"), 292 + root: "../", 293 + input: "to/the/file.txt", 294 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 295 + // in this case for the unindexed resolver, which is not correct. 296 + expectedRealPath: "to/the/file.txt", 297 + }, 298 + { 299 + name: "abs root, relative nested request, direct, cwd deep within (double) symlink root", 300 + cwd: filepath.Join(relativeViaDoubleLink, "path", "to"), 301 + root: filepath.Join(absoluteViaDoubleLink, "path"), 302 + input: "to/the/file.txt", 303 + expectedRealPath: "to/the/file.txt", 304 + }, 305 + { 306 + name: "relative root, abs nested request, direct, cwd deep within (double) symlink root", 307 + cwd: filepath.Join(relativeViaDoubleLink, "path", "to"), 308 + root: "../", 309 + input: "/to/the/file.txt", 310 + // note: this is inconsistent with the directory resolver. The real path is essentially the virtual path 311 + // in this case for the unindexed resolver, which is not correct. 312 + expectedRealPath: "to/the/file.txt", 313 + }, 314 + { 315 + name: "abs root, abs nested request, direct, cwd deep within (double) symlink root", 316 + cwd: filepath.Join(relativeViaDoubleLink, "path", "to"), 317 + root: filepath.Join(absoluteViaDoubleLink, "path"), 318 + input: "/to/the/file.txt", 319 + expectedRealPath: "to/the/file.txt", 320 + }, 321 + // link to outside of root cases... 322 + { 323 + name: "relative root, relative request, abs indirect (outside of root)", 324 + root: filepath.Join(relative, "path"), 325 + input: "to/the/abs-outside.txt", 326 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 327 + expectedVirtualPath: "to/the/abs-outside.txt", 328 + }, 329 + { 330 + name: "abs root, relative request, abs indirect (outside of root)", 331 + root: filepath.Join(absolute, "path"), 332 + input: "to/the/abs-outside.txt", 333 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 334 + expectedVirtualPath: "to/the/abs-outside.txt", 335 + }, 336 + { 337 + name: "relative root, abs request, abs indirect (outside of root)", 338 + root: filepath.Join(relative, "path"), 339 + input: "/to/the/abs-outside.txt", 340 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 341 + expectedVirtualPath: "to/the/abs-outside.txt", 342 + }, 343 + { 344 + name: "abs root, abs request, abs indirect (outside of root)", 345 + root: filepath.Join(absolute, "path"), 346 + input: "/to/the/abs-outside.txt", 347 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 348 + expectedVirtualPath: "to/the/abs-outside.txt", 349 + }, 350 + { 351 + name: "relative root, relative request, relative indirect (outside of root)", 352 + root: filepath.Join(relative, "path"), 353 + input: "to/the/rel-outside.txt", 354 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 355 + // TODO: the real path is not correct 356 + expectedRealPath: "../somewhere/outside.txt", 357 + expectedVirtualPath: "to/the/rel-outside.txt", 358 + }, 359 + { 360 + name: "abs root, relative request, relative indirect (outside of root)", 361 + root: filepath.Join(absolute, "path"), 362 + input: "to/the/rel-outside.txt", 363 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 364 + // TODO: the real path is not correct 365 + expectedRealPath: "../somewhere/outside.txt", 366 + expectedVirtualPath: "to/the/rel-outside.txt", 367 + }, 368 + { 369 + name: "relative root, abs request, relative indirect (outside of root)", 370 + root: filepath.Join(relative, "path"), 371 + input: "/to/the/rel-outside.txt", 372 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 373 + // TODO: the real path is not correct 374 + expectedRealPath: "../somewhere/outside.txt", 375 + expectedVirtualPath: "to/the/rel-outside.txt", 376 + }, 377 + { 378 + name: "abs root, abs request, relative indirect (outside of root)", 379 + root: filepath.Join(absolute, "path"), 380 + input: "/to/the/rel-outside.txt", 381 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 382 + // TODO: the real path is not correct 383 + expectedRealPath: "../somewhere/outside.txt", 384 + expectedVirtualPath: "to/the/rel-outside.txt", 385 + }, 386 + // link to outside of root cases... cwd within symlink root 387 + { 388 + name: "relative root, relative request, abs indirect (outside of root), cwd within symlink root", 389 + cwd: relativeViaLink, 390 + root: "path", 391 + input: "to/the/abs-outside.txt", 392 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 393 + expectedVirtualPath: "to/the/abs-outside.txt", 394 + }, 395 + { 396 + name: "abs root, relative request, abs indirect (outside of root), cwd within symlink root", 397 + cwd: relativeViaLink, 398 + root: filepath.Join(absolute, "path"), 399 + input: "to/the/abs-outside.txt", 400 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 401 + expectedVirtualPath: "to/the/abs-outside.txt", 402 + }, 403 + { 404 + name: "relative root, abs request, abs indirect (outside of root), cwd within symlink root", 405 + cwd: relativeViaLink, 406 + root: "path", 407 + input: "/to/the/abs-outside.txt", 408 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 409 + expectedVirtualPath: "to/the/abs-outside.txt", 410 + }, 411 + { 412 + name: "abs root, abs request, abs indirect (outside of root), cwd within symlink root", 413 + cwd: relativeViaLink, 414 + root: filepath.Join(absolute, "path"), 415 + input: "/to/the/abs-outside.txt", 416 + expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 417 + expectedVirtualPath: "to/the/abs-outside.txt", 418 + }, 419 + { 420 + name: "relative root, relative request, relative indirect (outside of root), cwd within symlink root", 421 + cwd: relativeViaLink, 422 + root: "path", 423 + input: "to/the/rel-outside.txt", 424 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 425 + // TODO: the real path is not correct 426 + expectedRealPath: "../somewhere/outside.txt", 427 + expectedVirtualPath: "to/the/rel-outside.txt", 428 + }, 429 + { 430 + name: "abs root, relative request, relative indirect (outside of root), cwd within symlink root", 431 + cwd: relativeViaLink, 432 + root: filepath.Join(absolute, "path"), 433 + input: "to/the/rel-outside.txt", 434 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 435 + // TODO: the real path is not correct 436 + expectedRealPath: "../somewhere/outside.txt", 437 + expectedVirtualPath: "to/the/rel-outside.txt", 438 + }, 439 + { 440 + name: "relative root, abs request, relative indirect (outside of root), cwd within symlink root", 441 + cwd: relativeViaLink, 442 + root: "path", 443 + input: "/to/the/rel-outside.txt", 444 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 445 + // TODO: the real path is not correct 446 + expectedRealPath: "../somewhere/outside.txt", 447 + expectedVirtualPath: "to/the/rel-outside.txt", 448 + }, 449 + { 450 + name: "abs root, abs request, relative indirect (outside of root), cwd within symlink root", 451 + cwd: relativeViaLink, 452 + root: filepath.Join(absolute, "path"), 453 + input: "/to/the/rel-outside.txt", 454 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 455 + // TODO: the real path is not correct 456 + expectedRealPath: "../somewhere/outside.txt", 457 + expectedVirtualPath: "to/the/rel-outside.txt", 458 + }, 459 + { 460 + name: "relative root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root", 461 + cwd: relativeViaDoubleLink, 462 + root: "path", 463 + input: "to/the/rel-outside.txt", 464 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 465 + // TODO: the real path is not correct 466 + expectedRealPath: "../somewhere/outside.txt", 467 + expectedVirtualPath: "to/the/rel-outside.txt", 468 + }, 469 + { 470 + name: "abs root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root", 471 + cwd: relativeViaDoubleLink, 472 + root: filepath.Join(absolute, "path"), 473 + input: "to/the/rel-outside.txt", 474 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 475 + // TODO: the real path is not correct 476 + expectedRealPath: "../somewhere/outside.txt", 477 + expectedVirtualPath: "to/the/rel-outside.txt", 478 + }, 479 + { 480 + name: "relative root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root", 481 + cwd: relativeViaDoubleLink, 482 + root: "path", 483 + input: "/to/the/rel-outside.txt", 484 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 485 + // TODO: the real path is not correct 486 + expectedRealPath: "../somewhere/outside.txt", 487 + expectedVirtualPath: "to/the/rel-outside.txt", 488 + }, 489 + { 490 + name: "abs root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root", 491 + cwd: relativeViaDoubleLink, 492 + root: filepath.Join(absolute, "path"), 493 + input: "/to/the/rel-outside.txt", 494 + //expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"), 495 + // TODO: the real path is not correct 496 + expectedRealPath: "../somewhere/outside.txt", 497 + expectedVirtualPath: "to/the/rel-outside.txt", 498 + }, 499 + } 500 + for _, c := range cases { 501 + t.Run(c.name, func(t *testing.T) { 502 + 503 + // we need to mimic a shell, otherwise we won't get a path within a symlink 504 + targetPath := filepath.Join(testDir, c.cwd) 505 + t.Setenv("PWD", filepath.Clean(targetPath)) 506 + 507 + require.NoError(t, err) 508 + require.NoError(t, os.Chdir(targetPath)) 509 + t.Cleanup(func() { 510 + require.NoError(t, os.Chdir(testDir)) 511 + }) 512 + 513 + resolver := NewFromUnindexedDirectory(c.root) 514 + require.NotNil(t, resolver) 515 + 516 + refs, err := resolver.FilesByPath(c.input) 517 + require.NoError(t, err) 518 + if c.expectedRealPath == "" { 519 + require.Empty(t, refs) 520 + return 521 + } 522 + require.Len(t, refs, 1) 523 + assert.Equal(t, c.expectedRealPath, refs[0].RealPath, "real path different") 524 + assert.Equal(t, c.expectedVirtualPath, refs[0].VirtualPath, "virtual path different") 525 + }) 526 + } 527 + } 528 + 26 529 func Test_UnindexedDirectoryResolver_Basic(t *testing.T) { 27 530 wd, err := os.Getwd() 28 531 require.NoError(t, err) skipped 755 lines