mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 14:02:26 +01:00
fix: don't split real paths on !/ in LocalPath and ContainerPath
`LocalPath` searched `FullNestedPath()` for the last `!/`, which is just `RealPath` for a file not in an archive. A host file like `/data/Hello!/world.txt` came back as `/world.txt`, so lookups and exclusions ran against the wrong path even with nested cataloging off. `ContainerPath` had the same problem when `FullPath` was set to `RealPath`. Both now cut `RealPath` off first and only look for a separator in the entry chain after it, which can't contain `!/` since entry names with it are refused. Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -90,11 +90,14 @@ func (t *Traversal) FullTraversalArchivePath() string {
|
||||
// ContainerPath returns the full path of the archive directly holding the file at c, or blank for a
|
||||
// file on the scanned filesystem, whether or not its FullPath is set.
|
||||
func ContainerPath(c file.Coordinates) string {
|
||||
i := strings.LastIndex(c.FullPath, file.ArchivePathSeparator)
|
||||
if i < 0 {
|
||||
entries, ok := archiveEntries(c)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return c.FullPath[:i]
|
||||
if i := strings.LastIndex(entries, file.ArchivePathSeparator); i >= 0 {
|
||||
return c.RealPath + file.ArchivePathSeparator + entries[:i]
|
||||
}
|
||||
return c.RealPath
|
||||
}
|
||||
|
||||
// archiveEntries is the "!/"-delimited chain of entry paths after RealPath, reporting false for a file
|
||||
|
||||
@@ -32,6 +32,9 @@ func TestContainerPath(t *testing.T) {
|
||||
assert.Equal(t, "", ContainerPath(file.NewCoordinates("/app.war", "")))
|
||||
assert.Equal(t, "", ContainerPath(file.Coordinates{RealPath: "/app.war", FullPath: "/app.war"}), "a top-level file whose FullPath is set")
|
||||
assert.Equal(t, "", ContainerPath(file.Coordinates{RealPath: "/odd!/name"}), "a separator in a top-level real path is not an archive boundary")
|
||||
assert.Equal(t, "", ContainerPath(file.Coordinates{RealPath: "/odd!/name", FullPath: "/odd!/name"}), "nor when FullPath is set")
|
||||
assert.Equal(t, "/odd!/name.zip", ContainerPath(locationIn("/odd!/name.zip", "a.txt").Coordinates))
|
||||
assert.Equal(t, "/odd!/name.zip!/b.jar", ContainerPath(locationIn("/odd!/name.zip", "b.jar!/a.txt").Coordinates))
|
||||
assert.Equal(t, "/app.war", ContainerPath(locationIn("/app.war", "WEB-INF/lib/dep.jar").Coordinates))
|
||||
assert.Equal(t, "/app.war!/WEB-INF/lib/dep.jar",
|
||||
ContainerPath(locationIn("/app.war", "WEB-INF/lib/dep.jar!/META-INF/MANIFEST.MF").Coordinates))
|
||||
|
||||
@@ -30,14 +30,18 @@ func (c Coordinates) FullNestedPath() string {
|
||||
return c.FullPath
|
||||
}
|
||||
|
||||
// LocalPath is the rooted path within the resolver holding the file: the segment of FullNestedPath after
|
||||
// the last archive separator, keeping the separator's slash, or RealPath for a file not within an archive.
|
||||
// LocalPath is the rooted path within the resolver holding the file: the last entry path in FullPath, or
|
||||
// RealPath for a file not within an archive. RealPath is cut off before looking for a separator, so a
|
||||
// "!/" in a real path is never taken for an archive boundary.
|
||||
func (c Coordinates) LocalPath() string {
|
||||
fullPath := c.FullNestedPath()
|
||||
if i := strings.LastIndex(fullPath, ArchivePathSeparator); i >= 0 {
|
||||
return fullPath[i+len(ArchivePathSeparator)-1:]
|
||||
entries, ok := strings.CutPrefix(c.FullPath, c.RealPath+ArchivePathSeparator)
|
||||
if !ok {
|
||||
return c.RealPath
|
||||
}
|
||||
return fullPath
|
||||
if i := strings.LastIndex(entries, ArchivePathSeparator); i >= 0 {
|
||||
entries = entries[i+len(ArchivePathSeparator):]
|
||||
}
|
||||
return "/" + entries
|
||||
}
|
||||
|
||||
func NewCoordinates(realPath, fsID string) Coordinates {
|
||||
|
||||
@@ -106,4 +106,8 @@ func TestCoordinates_LocalPath(t *testing.T) {
|
||||
assert.Equal(t, "/a.jar", NewCoordinates("/a.jar", "").LocalPath())
|
||||
assert.Equal(t, "/a.jar", Coordinates{RealPath: "/a.jar"}.LocalPath())
|
||||
assert.Equal(t, "/META-INF/MANIFEST.MF", Coordinates{RealPath: "/a.war", FullPath: "/a.war!/lib/b.jar!/META-INF/MANIFEST.MF"}.LocalPath())
|
||||
assert.Equal(t, "/data/Hello!/world.txt", NewCoordinates("/data/Hello!/world.txt", "").LocalPath(), "a separator in a real path is not an archive boundary")
|
||||
assert.Equal(t, "/data/Hello!/world.txt", Coordinates{RealPath: "/data/Hello!/world.txt", FullPath: "/data/Hello!/world.txt"}.LocalPath())
|
||||
assert.Equal(t, "/x.txt", Coordinates{RealPath: "/data/Hello!/a.zip", FullPath: "/data/Hello!/a.zip!/x.txt"}.LocalPath())
|
||||
assert.Equal(t, "/x.txt", Coordinates{RealPath: "/data/Hello!/a.zip", FullPath: "/data/Hello!/a.zip!/b.jar!/x.txt"}.LocalPath())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user