github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/repo/apk/apk.go (about) 1 package apk 2 3 import ( 4 "bufio" 5 "context" 6 "os" 7 "regexp" 8 9 "golang.org/x/exp/slices" 10 "golang.org/x/xerrors" 11 12 ver "github.com/aquasecurity/go-version/pkg/version" 13 "github.com/devseccon/trivy/pkg/fanal/analyzer" 14 "github.com/devseccon/trivy/pkg/fanal/types" 15 ) 16 17 func init() { 18 analyzer.RegisterAnalyzer(&apkRepoAnalyzer{}) 19 } 20 21 const version = 1 22 const edgeVersion = "edge" 23 24 var ( 25 requiredFiles = []string{"etc/apk/repositories"} 26 urlParseRegexp = regexp.MustCompile(`(https*|ftp)://[0-9A-Za-z.-]+/([A-Za-z]+)/v?([0-9A-Za-z_.-]+)/`) 27 ) 28 29 type apkRepoAnalyzer struct{} 30 31 func (a apkRepoAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { 32 scanner := bufio.NewScanner(input.Content) 33 var osFamily types.OSType 34 var repoVer string 35 for scanner.Scan() { 36 line := scanner.Text() 37 38 m := urlParseRegexp.FindStringSubmatch(line) 39 if len(m) != 4 { 40 continue 41 } 42 43 newOSFamily := types.OSType(m[2]) 44 newVersion := m[3] 45 46 // Find OS Family 47 if osFamily != "" && osFamily != newOSFamily { 48 return nil, xerrors.Errorf("mixing different distributions in etc/apk/repositories: %s != %s", osFamily, newOSFamily) 49 } 50 osFamily = newOSFamily 51 52 // Find max Release version 53 switch { 54 case repoVer == "": 55 repoVer = newVersion 56 case repoVer == edgeVersion || newVersion == edgeVersion: 57 repoVer = edgeVersion 58 default: 59 oldVer, err := ver.Parse(repoVer) 60 if err != nil { 61 continue 62 } 63 newVer, err := ver.Parse(newVersion) 64 if err != nil { 65 continue 66 } 67 68 // Take the maximum version in apk repositories 69 if newVer.GreaterThan(oldVer) { 70 repoVer = newVersion 71 } 72 } 73 } 74 75 // Currently, we support only Alpine Linux in apk repositories. 76 if osFamily != types.Alpine || repoVer == "" { 77 return nil, nil 78 } 79 80 return &analyzer.AnalysisResult{ 81 Repository: &types.Repository{ 82 Family: osFamily, 83 Release: repoVer, 84 }, 85 }, nil 86 } 87 88 func (a apkRepoAnalyzer) Required(filePath string, _ os.FileInfo) bool { 89 return slices.Contains(requiredFiles, filePath) 90 } 91 92 func (a apkRepoAnalyzer) Type() analyzer.Type { 93 return analyzer.TypeApkRepo 94 } 95 96 func (a apkRepoAnalyzer) Version() int { 97 return version 98 }