mirror of
https://github.com/anchore/syft.git
synced 2026-11-02 07:26:34 +01:00
* swift: emit canonical purls without .git suffix or repeated name
Reported in anchore/syft#3961: the purl syft emits for Swift packages
parsed out of Package.resolved keeps the repository URLs .git suffix
and then re-appends the package name, producing
pkg:swift/github.com/apple/swift-nio-ssl.git/swift-nio-ssl@2.0.0
NVD / Grype cannot match that purl against the known
swift-nio-ssl@2.0.0 CVE (GHSA-frg3-gpcx-968f), so every Swift SBOM
produced by syft silently loses vulnerability coverage. cdxgen and
the wider purl ecosystem use the shorter form
pkg:swift/github.com/apple/swift-nio-ssl@2.0.0
which Grype does match.
Replace the ad-hoc strings.Replace with swiftNamespaceFromSourceURL,
which trims the common URL schemes, strips the ".git" suffix, and
drops a trailing /<name> segment so the namespace is only the
organisation path (e.g. github.com/apple). Existing test expectations
are updated to the new purl shape.
Fixes #3961
Signed-off-by: Sai Asish Y <say.apm35@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
* Revert unrelated consul binary classifier changes
The swift purl commit (ff5ffc37) accidentally bundled removal of the
consul GitDescribe and NUL-wrapped version matchers plus the 1.12.9 and
1.7.14 fixtures/test cases. That drops version detection for consul
binaries not carrying the CONSUL_VERSION string. Restore the binary
cataloger to its pre-commit state so this branch is swift-only.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
* swift: strip repeated name segment case-insensitively
Package.resolved identities are lowercased while the repo URL path may be
mixed-case (e.g. github.com/Apple/Swift-NIO vs identity swift-nio). The
case-sensitive TrimSuffix left the repo segment in the namespace for such
repos, reintroducing the duplicated-name purl. Compare the trailing segment
with EqualFold and add unit coverage for swiftPackageManagerPackageURL.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
---------
Signed-off-by: Sai Asish Y <say.apm35@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
package swift
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/anchore/packageurl-go"
|
|
"github.com/anchore/syft/syft/file"
|
|
"github.com/anchore/syft/syft/pkg"
|
|
)
|
|
|
|
func newSwiftPackageManagerPackage(name, version, sourceURL, revision string, locations ...file.Location) pkg.Package {
|
|
p := pkg.Package{
|
|
Name: name,
|
|
Version: version,
|
|
PURL: swiftPackageManagerPackageURL(name, version, sourceURL),
|
|
Locations: file.NewLocationSet(locations...),
|
|
Type: pkg.SwiftPkg,
|
|
Language: pkg.Swift,
|
|
Metadata: pkg.SwiftPackageManagerResolvedEntry{
|
|
Revision: revision,
|
|
},
|
|
}
|
|
|
|
p.SetID()
|
|
|
|
return p
|
|
}
|
|
|
|
func newCocoaPodsPackage(name, version, hash string, locations ...file.Location) pkg.Package {
|
|
p := pkg.Package{
|
|
Name: name,
|
|
Version: version,
|
|
PURL: cocoaPodsPackageURL(name, version),
|
|
Locations: file.NewLocationSet(locations...),
|
|
Type: pkg.CocoapodsPkg,
|
|
Language: pkg.Swift,
|
|
Metadata: pkg.CocoaPodfileLockEntry{
|
|
Checksum: hash,
|
|
},
|
|
}
|
|
|
|
p.SetID()
|
|
|
|
return p
|
|
}
|
|
|
|
func cocoaPodsPackageURL(name, version string) string {
|
|
var qualifiers packageurl.Qualifiers
|
|
|
|
return packageurl.NewPackageURL(
|
|
packageurl.TypeCocoapods,
|
|
"",
|
|
name,
|
|
version,
|
|
qualifiers,
|
|
"",
|
|
).ToString()
|
|
}
|
|
|
|
func swiftPackageManagerPackageURL(name, version, sourceURL string) string {
|
|
var qualifiers packageurl.Qualifiers
|
|
|
|
return packageurl.NewPackageURL(
|
|
packageurl.TypeSwift,
|
|
swiftNamespaceFromSourceURL(sourceURL, name),
|
|
name,
|
|
version,
|
|
qualifiers,
|
|
"",
|
|
).ToString()
|
|
}
|
|
|
|
// swiftNamespaceFromSourceURL derives the purl namespace (e.g.
|
|
// "github.com/apple") from a Swift Package.resolved source URL like
|
|
// "https://github.com/apple/swift-nio-ssl.git".
|
|
//
|
|
// Two bits of cleanup are needed compared with the previous
|
|
// strings.Replace(sourceURL, "https://", "", 1) behaviour:
|
|
//
|
|
// 1. Strip the ".git" suffix. Swift Package.resolved always carries the
|
|
// repository URL with a trailing ".git", but the purl spec uses the
|
|
// plain web path.
|
|
// 2. Drop the trailing /<name> segment. The previous code left the repo
|
|
// name in the namespace and then appended the package name again, so
|
|
// the emitted purl looked like
|
|
// pkg:swift/github.com/apple/swift-nio-ssl.git/swift-nio-ssl@2.0.0
|
|
// which Grype cannot match against NVD. The expected form is
|
|
// pkg:swift/github.com/apple/swift-nio-ssl@2.0.0
|
|
// which is also what cdxgen emits. See anchore/syft#3961.
|
|
func swiftNamespaceFromSourceURL(sourceURL, name string) string {
|
|
ns := sourceURL
|
|
for _, prefix := range []string{"https://", "http://", "git+ssh://", "ssh://"} {
|
|
ns = strings.TrimPrefix(ns, prefix)
|
|
}
|
|
ns = strings.TrimSuffix(ns, ".git")
|
|
// drop a trailing "/<name>" segment. Package.resolved identities are lowercased
|
|
// while the repo path may be mixed-case (e.g. github.com/Apple/Swift-NIO vs
|
|
// identity swift-nio), so compare case-insensitively.
|
|
if name != "" {
|
|
if idx := strings.LastIndex(ns, "/"); idx >= 0 && strings.EqualFold(ns[idx+1:], name) {
|
|
ns = ns[:idx]
|
|
}
|
|
}
|
|
return ns
|
|
}
|