Skip to content

Commit

Permalink
read relative etc/apk/repositories for alpine version when no OS prov…
Browse files Browse the repository at this point in the history
…ided

Signed-off-by: Avi Deitcher <avi@deitcher.net>
  • Loading branch information
deitch committed Feb 24, 2023
1 parent 0c05855 commit bab9c68
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
1 change: 1 addition & 0 deletions syft/pkg/cataloger/apkdb/cataloger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestCataloger_Globs(t *testing.T) {
pkgtest.NewCatalogTester().
FromDirectory(t, test.fixture).
ExpectsResolverContentQueries(test.expected).
IgnoreUnfulfilledPathResponses("etc/apk/repositories").
TestCataloger(t, NewApkdbCataloger())
})
}
Expand Down
57 changes: 55 additions & 2 deletions syft/pkg/cataloger/apkdb/parse_apk_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package apkdb
import (
"bufio"
"fmt"
"io"
"path"
"regexp"
"strconv"
"strings"

Expand All @@ -20,11 +22,41 @@ import (
// integrity check
var _ generic.Parser = parseApkDB

var (
repoRegex = regexp.MustCompile(`^https://.*\.alpinelinux\.org/alpine/v([^\/]+)/([a-zA-Z0-9_]+)$`)
newlineSplitRegex = regexp.MustCompile(`[\r \s\n]+`)
)

func init() {
repoRegex.Longest()
newlineSplitRegex.Longest()
}

// parseApkDB parses packages from a given APK installed DB file. For more
// information on specific fields, see https://wiki.alpinelinux.org/wiki/Apk_spec.
//
//nolint:funlen
func parseApkDB(_ source.FileResolver, env *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
//nolint:funlen,gocognit
func parseApkDB(resolver source.FileResolver, env *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
// find the repositories file from the the relative directory of the DB file
var repos []string
if resolver != nil {
reposLocation := path.Clean(path.Join(path.Dir(reader.Location.RealPath), "../../../etc/apk/repositories"))
paths, err := resolver.FilesByPath(reposLocation)
if err == nil && len(paths) > 0 {
reposContent, err := resolver.FileContentsByLocation(paths[0])
if err == nil {
reposB, err := io.ReadAll(reposContent)
if err == nil {
reposDirect := newlineSplitRegex.Split(string(reposB), -1)
for _, repo := range reposDirect {
if repo != "" {
repos = append(repos, repo)
}
}
}
}
}
}
scanner := bufio.NewScanner(reader)

var apks []pkg.ApkMetadata
Expand Down Expand Up @@ -101,6 +133,27 @@ func parseApkDB(_ source.FileResolver, env *generic.Environment, reader source.L
if env != nil {
r = env.LinuxRelease
}
// this is somewhat ugly, but better than completely failing when we can't find the release,
// e.g. embedded deeper in the tree, like containers or chroots.
// but we now have no way of handling different repository sources. On the other hand,
// we never could before this. At least now, we can handle some.
// This should get fixed with https://gitlab.alpinelinux.org/alpine/apk-tools/-/issues/10875
if r == nil {
for _, repo := range repos {
parts := repoRegex.FindAllStringSubmatch(repo, -1)
if len(parts) == 0 {
continue
}
// we confirmed that alpine is installed, so we can treat it as that.
// get the version
r = &linux.Release{
Name: "Alpine Linux",
ID: "alpine",
VersionID: parts[0][1],
}
break
}
}

pkgs := make([]pkg.Package, 0, len(apks))
for _, apk := range apks {
Expand Down

0 comments on commit bab9c68

Please sign in to comment.