mirror of
https://github.com/anchore/syft.git
synced 2026-11-02 15:36:41 +01:00
fix: don't infer archive nesting from paths in error text
`ProcessPathErrors` cut the `path="..."` it pulled out of an error at the first `!/` and built nested coordinates from it, so a host file with `!/` in its name was reported as a file inside an archive. - paths from error text are taken as plain real paths again, as on main - the php extension reader already has the location in hand, so it records the unknown against that instead of re-parsing the error (this is the one caller that could see a nested path). It also no longer defers `Close` on a nil reader when the read fails Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,6 @@ package unknown
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
@@ -20,7 +19,9 @@ func ProcessPathErrors(err error) error {
|
|||||||
if pathErrorRegex.MatchString(errText) {
|
if pathErrorRegex.MatchString(errText) {
|
||||||
foundPath := pathErrorRegex.ReplaceAllString(err.Error(), "$1")
|
foundPath := pathErrorRegex.ReplaceAllString(err.Error(), "$1")
|
||||||
if foundPath != "" {
|
if foundPath != "" {
|
||||||
return New(file.NewLocationFromCoordinates(pathCoordinates(foundPath)), err)
|
// a path in an error text is taken as is: nesting is never inferred from "!/" in it, since a real
|
||||||
|
// path can hold one too. A caller with the location in hand should use New instead
|
||||||
|
return New(file.NewLocation(foundPath), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unknowns, remainingErrors := ExtractCoordinateErrors(err)
|
unknowns, remainingErrors := ExtractCoordinateErrors(err)
|
||||||
@@ -32,13 +33,3 @@ func ProcessPathErrors(err error) error {
|
|||||||
}
|
}
|
||||||
return Join(out...)
|
return Join(out...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pathCoordinates names the file at a path from a resolver error, which for a file within an archive is
|
|
||||||
// a full path: the real path is what precedes the first archive separator.
|
|
||||||
func pathCoordinates(p string) file.Coordinates {
|
|
||||||
realPath, _, nested := strings.Cut(p, file.ArchivePathSeparator)
|
|
||||||
if !nested {
|
|
||||||
return file.NewCoordinates(p, "")
|
|
||||||
}
|
|
||||||
return file.Coordinates{RealPath: realPath, FullPath: p}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ func Test_ProcessPathErrors(t *testing.T) {
|
|||||||
Reason: fmt.Errorf(`path="/var/lib/thing" suffix`),
|
Reason: fmt.Errorf(`path="/var/lib/thing" suffix`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
errorText: `path="/data/Hello!/world.txt"`,
|
||||||
|
expected: &CoordinateError{
|
||||||
|
Coordinates: file.NewCoordinates("/data/Hello!/world.txt", ""),
|
||||||
|
Reason: fmt.Errorf(`path="/data/Hello!/world.txt"`),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
errorText: "all your base are belong to us",
|
errorText: "all your base are belong to us",
|
||||||
expected: nil,
|
expected: nil,
|
||||||
|
|||||||
@@ -182,10 +182,10 @@ func (p interpreterCataloger) catalogExtensions(resolver file.Resolver) ([]pkg.P
|
|||||||
|
|
||||||
func (p interpreterCataloger) catalogExtension(resolver file.Resolver, location file.Location) ([]pkg.Package, error) {
|
func (p interpreterCataloger) catalogExtension(resolver file.Resolver, location file.Location) ([]pkg.Package, error) {
|
||||||
reader, err := resolver.FileContentsByLocation(location)
|
reader, err := resolver.FileContentsByLocation(location)
|
||||||
defer internal.CloseAndLogError(reader, location.FullNestedPath())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, unknown.ProcessPathErrors(err)
|
return nil, unknown.New(location, err)
|
||||||
}
|
}
|
||||||
|
defer internal.CloseAndLogError(reader, location.FullNestedPath())
|
||||||
|
|
||||||
name, cls := p.getClassifier(location.FullNestedPath())
|
name, cls := p.getClassifier(location.FullNestedPath())
|
||||||
if name == "" || cls == nil {
|
if name == "" || cls == nil {
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/unknown"
|
||||||
"github.com/anchore/syft/syft/cpe"
|
"github.com/anchore/syft/syft/cpe"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -164,3 +166,17 @@ func Test_getClassifier_declaredCPESource(t *testing.T) {
|
|||||||
require.Len(t, cls.CPEs, 1)
|
require.Len(t, cls.CPEs, 1)
|
||||||
assert.Equal(t, cpe.DeclaredSource, cls.CPEs[0].Source)
|
assert.Equal(t, cpe.DeclaredSource, cls.CPEs[0].Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_catalogExtension_unreadableFileKeepsItsCoordinates(t *testing.T) {
|
||||||
|
nested := file.NewLocationFromCoordinates(file.Coordinates{
|
||||||
|
RealPath: "/app.tar",
|
||||||
|
FullPath: "/app.tar!/usr/lib/php83/modules/bcmath.so",
|
||||||
|
})
|
||||||
|
c := NewInterpreterCataloger().(interpreterCataloger)
|
||||||
|
|
||||||
|
_, err := c.catalogExtension(file.NewMockResolverForPaths(), nested)
|
||||||
|
|
||||||
|
var coordinateErr *unknown.CoordinateError
|
||||||
|
require.ErrorAs(t, err, &coordinateErr)
|
||||||
|
assert.Equal(t, nested.Coordinates, coordinateErr.Coordinates)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user