Compare commits
	
		
			24 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					96333f38c9 | ||
| 
						 | 
					8b5d1c8e92 | ||
| 
						 | 
					dea80f860c | ||
| 
						 | 
					6eb4c5a5fe | ||
| 
						 | 
					b219a8495e | ||
| 
						 | 
					eb87d5d4e1 | ||
| 
						 | 
					6963442a5e | ||
| 
						 | 
					f7299b9dba | ||
| 
						 | 
					379fc8a1a1 | ||
| 
						 | 
					947fbbb29e | ||
| 
						 | 
					06d2032c9c | ||
| 
						 | 
					d055c48827 | ||
| 
						 | 
					2a00339da1 | ||
| 
						 | 
					2d959b3af8 | ||
| 
						 | 
					595e26db41 | ||
| 
						 | 
					1e457320c5 | ||
| 
						 | 
					a06e689502 | ||
| 
						 | 
					ca3f6b1dbf | ||
| 
						 | 
					f1c78e42a2 | ||
| 
						 | 
					2f3b8bf3cc | ||
| 
						 | 
					ab54266f9e | ||
| 
						 | 
					d79d138440 | ||
| 
						 | 
					139f3a81b6 | ||
| 
						 | 
					d1a617cfff | 
@@ -88,7 +88,7 @@ NOW=$(shell date --iso-8601=seconds)
 | 
			
		||||
NOW_JSON_DIR := '${BASE_DIR}/$(NOW)'
 | 
			
		||||
ONE_SEC_AFTER=$(shell date -d '+1 second' --iso-8601=seconds)
 | 
			
		||||
ONE_SEC_AFTER_JSON_DIR := '${BASE_DIR}/$(ONE_SEC_AFTER)'
 | 
			
		||||
LIBS := 'bundler' 'pip' 'pipenv' 'poetry' 'composer' 'npm' 'yarn' 'cargo' 'gomod' 'gosum' 'gobinary' 'jar' 'pom' 'nuget-lock' 'nuget-config' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
 | 
			
		||||
LIBS := 'bundler' 'pip' 'pipenv' 'poetry' 'composer' 'npm' 'yarn' 'pnpm' 'cargo' 'gomod' 'gosum' 'gobinary' 'jar' 'pom' 'nuget-lock' 'nuget-config' 'dotnet-deps' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
 | 
			
		||||
 | 
			
		||||
diff:
 | 
			
		||||
	# git clone git@github.com:vulsio/vulsctl.git
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,8 @@
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Vulnerability scanner for Linux/FreeBSD, agent-less, written in Go.
 | 
			
		||||
We have a slack team. [Join slack team](http://goo.gl/forms/xm5KFo35tu)
 | 
			
		||||
Vulnerability scanner for Linux/FreeBSD, agent-less, written in Go.  
 | 
			
		||||
We have a slack team. [Join slack team](https://join.slack.com/t/vuls-github/shared_invite/zt-1fculjwj4-6nex2JNE7DpOSiKZ1ztDFw)  
 | 
			
		||||
Twitter: [@vuls_en](https://twitter.com/vuls_en)
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								config/os.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								config/os.go
									
									
									
									
									
								
							@@ -41,8 +41,8 @@ func GetEOL(family, release string) (eol EOL, found bool) {
 | 
			
		||||
	case constant.Amazon:
 | 
			
		||||
		eol, found = map[string]EOL{
 | 
			
		||||
			"1":    {StandardSupportUntil: time.Date(2023, 6, 30, 23, 59, 59, 0, time.UTC)},
 | 
			
		||||
			"2":    {},
 | 
			
		||||
			"2022": {},
 | 
			
		||||
			"2":    {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
 | 
			
		||||
			"2022": {StandardSupportUntil: time.Date(2026, 6, 30, 23, 59, 59, 0, time.UTC)},
 | 
			
		||||
		}[getAmazonLinuxVersion(release)]
 | 
			
		||||
	case constant.RedHat:
 | 
			
		||||
		// https://access.redhat.com/support/policy/updates/errata
 | 
			
		||||
@@ -87,7 +87,7 @@ func GetEOL(family, release string) (eol EOL, found bool) {
 | 
			
		||||
	case constant.Rocky:
 | 
			
		||||
		eol, found = map[string]EOL{
 | 
			
		||||
			"8": {StandardSupportUntil: time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC)},
 | 
			
		||||
			// "9": {StandardSupportUntil: time.Date(2032, 5, 31, 23, 59, 59, 0, time.UTC)},
 | 
			
		||||
			"9": {StandardSupportUntil: time.Date(2032, 5, 31, 23, 59, 59, 0, time.UTC)},
 | 
			
		||||
		}[major(release)]
 | 
			
		||||
	case constant.Oracle:
 | 
			
		||||
		eol, found = map[string]EOL{
 | 
			
		||||
@@ -99,13 +99,19 @@ func GetEOL(family, release string) (eol EOL, found bool) {
 | 
			
		||||
			"5": {Ended: true},
 | 
			
		||||
			"6": {
 | 
			
		||||
				StandardSupportUntil: time.Date(2021, 3, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
				ExtendedSupportUntil: time.Date(2024, 3, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
				ExtendedSupportUntil: time.Date(2024, 6, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			},
 | 
			
		||||
			"7": {
 | 
			
		||||
				StandardSupportUntil: time.Date(2024, 7, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
				ExtendedSupportUntil: time.Date(2026, 6, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			},
 | 
			
		||||
			"8": {
 | 
			
		||||
				StandardSupportUntil: time.Date(2029, 7, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
				ExtendedSupportUntil: time.Date(2031, 7, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			},
 | 
			
		||||
			"9": {
 | 
			
		||||
				StandardSupportUntil: time.Date(2032, 6, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
				ExtendedSupportUntil: time.Date(2034, 6, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			},
 | 
			
		||||
		}[major(release)]
 | 
			
		||||
	case constant.Debian:
 | 
			
		||||
@@ -160,6 +166,9 @@ func GetEOL(family, release string) (eol EOL, found bool) {
 | 
			
		||||
				StandardSupportUntil: time.Date(2027, 4, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
				ExtendedSupportUntil: time.Date(2032, 4, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			},
 | 
			
		||||
			"22.10": {
 | 
			
		||||
				StandardSupportUntil: time.Date(2023, 7, 20, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			},
 | 
			
		||||
		}[release]
 | 
			
		||||
	case constant.OpenSUSE:
 | 
			
		||||
		// https://en.opensuse.org/Lifetime
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
			found:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "amazon linux 2024 not found",
 | 
			
		||||
			fields:   fields{family: Amazon, release: "2024 (Amazon Linux)"},
 | 
			
		||||
			now:      time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
			found:    false,
 | 
			
		||||
		},
 | 
			
		||||
		//RHEL
 | 
			
		||||
		{
 | 
			
		||||
			name:     "RHEL6 eol",
 | 
			
		||||
@@ -178,14 +186,30 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
 | 
			
		||||
			found:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Rocky Linux 9 Not Found",
 | 
			
		||||
			name:     "Rocky Linux 9 supported",
 | 
			
		||||
			fields:   fields{family: Rocky, release: "9"},
 | 
			
		||||
			now:      time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
			found:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Rocky Linux 10 Not Found",
 | 
			
		||||
			fields:   fields{family: Rocky, release: "10"},
 | 
			
		||||
			now:      time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
			found:    false,
 | 
			
		||||
		},
 | 
			
		||||
		//Oracle
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Oracle Linux 6 eol",
 | 
			
		||||
			fields:   fields{family: Oracle, release: "6"},
 | 
			
		||||
			now:      time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
			found:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Oracle Linux 7 supported",
 | 
			
		||||
			fields:   fields{family: Oracle, release: "7"},
 | 
			
		||||
@@ -203,16 +227,16 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
 | 
			
		||||
			found:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Oracle Linux 6 eol",
 | 
			
		||||
			fields:   fields{family: Oracle, release: "6"},
 | 
			
		||||
			name:     "Oracle Linux 9 supported",
 | 
			
		||||
			fields:   fields{family: Oracle, release: "9"},
 | 
			
		||||
			now:      time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
			found:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Oracle Linux 9 not found",
 | 
			
		||||
			fields:   fields{family: Oracle, release: "9"},
 | 
			
		||||
			name:     "Oracle Linux 10 not found",
 | 
			
		||||
			fields:   fields{family: Oracle, release: "10"},
 | 
			
		||||
			now:      time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
@@ -315,6 +339,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Ubuntu 22.10 supported",
 | 
			
		||||
			fields:   fields{family: Ubuntu, release: "22.10"},
 | 
			
		||||
			now:      time.Date(2022, 5, 1, 23, 59, 59, 0, time.UTC),
 | 
			
		||||
			found:    true,
 | 
			
		||||
			stdEnded: false,
 | 
			
		||||
			extEnded: false,
 | 
			
		||||
		},
 | 
			
		||||
		//Debian
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Debian 9 supported",
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/aquasecurity/fanal/analyzer/os"
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/fanal/analyzer/os"
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/types"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										139
									
								
								cti/cti.go
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								cti/cti.go
									
									
									
									
									
								
							@@ -660,7 +660,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name: "CAPEC-35: Leverage Executable Code in Non-Executable Files",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-36": {
 | 
			
		||||
		Name: "CAPEC-36: Using Unpublished Interfaces",
 | 
			
		||||
		Name: "CAPEC-36: Using Unpublished Interfaces or Functionality",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-37": {
 | 
			
		||||
		Name: "CAPEC-37: Retrieve Embedded Sensitive Data",
 | 
			
		||||
@@ -831,7 +831,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name: "CAPEC-442: Infected Software",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-443": {
 | 
			
		||||
		Name: "CAPEC-443: Malicious Logic Inserted Into Product Software by Authorized Developer",
 | 
			
		||||
		Name: "CAPEC-443: Malicious Logic Inserted Into Product by Authorized Developer",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-444": {
 | 
			
		||||
		Name: "CAPEC-444: Development Alteration",
 | 
			
		||||
@@ -840,7 +840,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name: "CAPEC-445: Malicious Logic Insertion into Product Software via Configuration Management Manipulation",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-446": {
 | 
			
		||||
		Name: "CAPEC-446: Malicious Logic Insertion into Product Software via Inclusion of 3rd Party Component Dependency",
 | 
			
		||||
		Name: "CAPEC-446: Malicious Logic Insertion into Product via Inclusion of Third-Party Component",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-447": {
 | 
			
		||||
		Name: "CAPEC-447: Design Alteration",
 | 
			
		||||
@@ -1382,9 +1382,6 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	"CAPEC-628": {
 | 
			
		||||
		Name: "CAPEC-628: Carry-Off GPS Attack",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-629": {
 | 
			
		||||
		Name: "CAPEC-629: Unauthorized Use of Device Resources",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-63": {
 | 
			
		||||
		Name: "CAPEC-63: Cross-Site Scripting (XSS)",
 | 
			
		||||
	},
 | 
			
		||||
@@ -1464,7 +1461,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name: "CAPEC-652: Use of Known Kerberos Credentials",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-653": {
 | 
			
		||||
		Name: "CAPEC-653: Use of Known Windows Credentials",
 | 
			
		||||
		Name: "CAPEC-653: Use of Known Operating System Credentials",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-654": {
 | 
			
		||||
		Name: "CAPEC-654: Credential Prompt Impersonation",
 | 
			
		||||
@@ -1553,9 +1550,39 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	"CAPEC-681": {
 | 
			
		||||
		Name: "CAPEC-681: Exploitation of Improperly Controlled Hardware Security Identifiers",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-682": {
 | 
			
		||||
		Name: "CAPEC-682: Exploitation of Firmware or ROM Code with Unpatchable Vulnerabilities",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-69": {
 | 
			
		||||
		Name: "CAPEC-69: Target Programs with Elevated Privileges",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-690": {
 | 
			
		||||
		Name: "CAPEC-690: Metadata Spoofing",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-691": {
 | 
			
		||||
		Name: "CAPEC-691: Spoof Open-Source Software Metadata",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-692": {
 | 
			
		||||
		Name: "CAPEC-692: Spoof Version Control System Commit Metadata",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-693": {
 | 
			
		||||
		Name: "CAPEC-693: StarJacking",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-694": {
 | 
			
		||||
		Name: "CAPEC-694: System Location Discovery",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-695": {
 | 
			
		||||
		Name: "CAPEC-695: Repo Jacking",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-696": {
 | 
			
		||||
		Name: "CAPEC-696: Load Value Injection",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-697": {
 | 
			
		||||
		Name: "CAPEC-697: DHCP Spoofing",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-698": {
 | 
			
		||||
		Name: "CAPEC-698: Install Malicious Extension",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-7": {
 | 
			
		||||
		Name: "CAPEC-7: Blind SQL Injection",
 | 
			
		||||
	},
 | 
			
		||||
@@ -1596,7 +1623,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name: "CAPEC-80: Using UTF-8 Encoding to Bypass Validation Logic",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-81": {
 | 
			
		||||
		Name: "CAPEC-81: Web Logs Tampering",
 | 
			
		||||
		Name: "CAPEC-81: Web Server Logs Tampering",
 | 
			
		||||
	},
 | 
			
		||||
	"CAPEC-83": {
 | 
			
		||||
		Name: "CAPEC-83: XPath Injection",
 | 
			
		||||
@@ -1814,6 +1841,18 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1027.006: HTML Smuggling",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1027.007": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1027.007: Dynamic API Resolution",
 | 
			
		||||
		Platforms: []string{"Windows"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1027.008": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1027.008: Stripped Payloads",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1027.009": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1027.009: Embedded Payloads",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1029": {
 | 
			
		||||
		Name:      "TA0010: Exfiltration => T1029: Scheduled Transfer",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
@@ -2087,8 +2126,8 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Platforms: []string{"Azure AD", "Google Workspace", "IaaS", "Office 365", "SaaS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1070": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070: Indicator Removal on Host",
 | 
			
		||||
		Platforms: []string{"Containers", "Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070: Indicator Removal",
 | 
			
		||||
		Platforms: []string{"Containers", "Google Workspace", "Linux", "Network", "Office 365", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1070.001": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070.001: Clear Windows Event Logs",
 | 
			
		||||
@@ -2114,6 +2153,18 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070.006: Timestomp",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1070.007": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070.007: Clear Network Connection History and Configurations",
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1070.008": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070.008: Clear Mailbox Data",
 | 
			
		||||
		Platforms: []string{"Google Workspace", "Linux", "Office 365", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1070.009": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1070.009: Clear Persistence",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1071": {
 | 
			
		||||
		Name:      "TA0011: Command and Control => T1071: Application Layer Protocol",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
@@ -2152,7 +2203,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1078": {
 | 
			
		||||
		Name:      "TA0001: Initial Access, TA0003: Persistence, TA0004: Privilege Escalation, TA0005: Defense Evasion => T1078: Valid Accounts",
 | 
			
		||||
		Platforms: []string{"Azure AD", "Containers", "Google Workspace", "IaaS", "Linux", "Office 365", "SaaS", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"Azure AD", "Containers", "Google Workspace", "IaaS", "Linux", "Network", "Office 365", "SaaS", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1078.001": {
 | 
			
		||||
		Name:      "TA0001: Initial Access, TA0003: Persistence, TA0004: Privilege Escalation, TA0005: Defense Evasion => T1078.001: Default Accounts",
 | 
			
		||||
@@ -2504,7 +2555,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1199": {
 | 
			
		||||
		Name:      "TA0001: Initial Access => T1199: Trusted Relationship",
 | 
			
		||||
		Platforms: []string{"IaaS", "Linux", "SaaS", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"IaaS", "Linux", "Office 365", "SaaS", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1200": {
 | 
			
		||||
		Name:      "TA0001: Initial Access => T1200: Hardware Additions",
 | 
			
		||||
@@ -2546,6 +2597,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0011: Command and Control => T1205.001: Port Knocking",
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1205.002": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0011: Command and Control => T1205.002: Socket Filters",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1207": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1207: Rogue Domain Controller",
 | 
			
		||||
		Platforms: []string{"Windows"},
 | 
			
		||||
@@ -2780,7 +2835,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1505": {
 | 
			
		||||
		Name:      "TA0003: Persistence => T1505: Server Software Component",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1505.001": {
 | 
			
		||||
		Name:      "TA0003: Persistence => T1505.001: SQL Stored Procedures",
 | 
			
		||||
@@ -2792,7 +2847,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1505.003": {
 | 
			
		||||
		Name:      "TA0003: Persistence => T1505.003: Web Shell",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1505.004": {
 | 
			
		||||
		Name:      "TA0003: Persistence => T1505.004: IIS Components",
 | 
			
		||||
@@ -2827,8 +2882,8 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1530": {
 | 
			
		||||
		Name:      "TA0009: Collection => T1530: Data from Cloud Storage Object",
 | 
			
		||||
		Platforms: []string{"IaaS"},
 | 
			
		||||
		Name:      "TA0009: Collection => T1530: Data from Cloud Storage",
 | 
			
		||||
		Platforms: []string{"IaaS", "SaaS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1531": {
 | 
			
		||||
		Name:      "TA0040: Impact => T1531: Account Access Removal",
 | 
			
		||||
@@ -2900,7 +2955,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1546": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0004: Privilege Escalation => T1546: Event Triggered Execution",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"IaaS", "Linux", "Office 365", "SaaS", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1546.001": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0004: Privilege Escalation => T1546.001: Change Default File Association",
 | 
			
		||||
@@ -2962,6 +3017,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0004: Privilege Escalation => T1546.015: Component Object Model Hijacking",
 | 
			
		||||
		Platforms: []string{"Windows"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1546.016": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0004: Privilege Escalation => T1546.016: Installer Packages",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1547": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0004: Privilege Escalation => T1547: Boot or Logon Autostart Execution",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
@@ -3048,7 +3107,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1550.001": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion, TA0008: Lateral Movement => T1550.001: Application Access Token",
 | 
			
		||||
		Platforms: []string{"Containers", "Google Workspace", "Office 365", "SaaS"},
 | 
			
		||||
		Platforms: []string{"Azure AD", "Containers", "Google Workspace", "IaaS", "Office 365", "SaaS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1550.002": {
 | 
			
		||||
		Name:      "TA0005: Defense Evasion, TA0008: Lateral Movement => T1550.002: Pass the Hash",
 | 
			
		||||
@@ -3152,7 +3211,7 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
	},
 | 
			
		||||
	"T1556": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0006: Credential Access => T1556: Modify Authentication Process",
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"Azure AD", "Google Workspace", "IaaS", "Linux", "Network", "Office 365", "SaaS", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1556.001": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0006: Credential Access => T1556.001: Domain Controller Authentication",
 | 
			
		||||
@@ -3174,9 +3233,17 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0006: Credential Access => T1556.005: Reversible Encryption",
 | 
			
		||||
		Platforms: []string{"Windows"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1556.006": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0006: Credential Access => T1556.006: Multi-Factor Authentication",
 | 
			
		||||
		Platforms: []string{"Azure AD", "Google Workspace", "IaaS", "Linux", "Office 365", "SaaS", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1556.007": {
 | 
			
		||||
		Name:      "TA0003: Persistence, TA0005: Defense Evasion, TA0006: Credential Access => T1556.007: Hybrid Identity",
 | 
			
		||||
		Platforms: []string{"Azure AD", "Google Workspace", "IaaS", "Office 365", "SaaS", "Windows"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1557": {
 | 
			
		||||
		Name:      "TA0006: Credential Access, TA0009: Collection => T1557: Adversary-in-the-Middle",
 | 
			
		||||
		Platforms: []string{"Linux", "Windows", "macOS"},
 | 
			
		||||
		Platforms: []string{"Linux", "Network", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1557.001": {
 | 
			
		||||
		Name:      "TA0006: Credential Access, TA0009: Collection => T1557.001: LLMNR/NBT-NS Poisoning and SMB Relay",
 | 
			
		||||
@@ -3550,6 +3617,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1583.006: Web Services",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1583.007": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1583.007: Serverless",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1584": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1584: Compromise Infrastructure",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
@@ -3578,6 +3649,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1584.006: Web Services",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1584.007": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1584.007: Serverless",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1585": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1585: Establish Accounts",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
@@ -3590,6 +3665,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1585.002: Email Accounts",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1585.003": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1585.003: Cloud Accounts",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1586": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1586: Compromise Accounts",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
@@ -3602,6 +3681,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1586.002: Email Accounts",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1586.003": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1586.003: Cloud Accounts",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1587": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1587: Develop Capabilities",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
@@ -3746,6 +3829,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0043: Reconnaissance => T1593.002: Search Engines",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1593.003": {
 | 
			
		||||
		Name:      "TA0043: Reconnaissance => T1593.003: Code Repositories",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1594": {
 | 
			
		||||
		Name:      "TA0043: Reconnaissance => T1594: Search Victim-Owned Websites",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
@@ -3898,6 +3985,10 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1608.005: Link Target",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1608.006": {
 | 
			
		||||
		Name:      "TA0042: Resource Development => T1608.006: SEO Poisoning",
 | 
			
		||||
		Platforms: []string{"PRE"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1609": {
 | 
			
		||||
		Name:      "TA0002: Execution => T1609: Container Administration Command",
 | 
			
		||||
		Platforms: []string{"Containers"},
 | 
			
		||||
@@ -3950,4 +4041,12 @@ var TechniqueDict = map[string]Technique{
 | 
			
		||||
		Name:      "TA0005: Defense Evasion => T1647: Plist File Modification",
 | 
			
		||||
		Platforms: []string{"macOS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1648": {
 | 
			
		||||
		Name:      "TA0002: Execution => T1648: Serverless Execution",
 | 
			
		||||
		Platforms: []string{"IaaS", "Office 365", "SaaS"},
 | 
			
		||||
	},
 | 
			
		||||
	"T1649": {
 | 
			
		||||
		Name:      "TA0006: Credential Access => T1649: Steal or Forge Authentication Certificates",
 | 
			
		||||
		Platforms: []string{"Azure AD", "Linux", "Windows", "macOS"},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								cwe/cwe.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								cwe/cwe.go
									
									
									
									
									
								
							@@ -5,6 +5,7 @@ var CweTopTwentyfives = map[string]map[string]string{
 | 
			
		||||
	"2019": cweTopTwentyfive2019,
 | 
			
		||||
	"2020": cweTopTwentyfive2020,
 | 
			
		||||
	"2021": cweTopTwentyfive2021,
 | 
			
		||||
	"2022": cweTopTwentyfive2022,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var cweTopTwentyfive2019 = map[string]string{
 | 
			
		||||
@@ -91,9 +92,38 @@ var cweTopTwentyfive2021 = map[string]string{
 | 
			
		||||
	"77":  "25",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var cweTopTwentyfive2022 = map[string]string{
 | 
			
		||||
	"787": "1",
 | 
			
		||||
	"79":  "2",
 | 
			
		||||
	"89":  "3",
 | 
			
		||||
	"20":  "4",
 | 
			
		||||
	"125": "5",
 | 
			
		||||
	"78":  "6",
 | 
			
		||||
	"416": "7",
 | 
			
		||||
	"22":  "8",
 | 
			
		||||
	"352": "9",
 | 
			
		||||
	"434": "10",
 | 
			
		||||
	"476": "11",
 | 
			
		||||
	"502": "12",
 | 
			
		||||
	"190": "13",
 | 
			
		||||
	"287": "14",
 | 
			
		||||
	"798": "16",
 | 
			
		||||
	"862": "16",
 | 
			
		||||
	"77":  "17",
 | 
			
		||||
	"306": "18",
 | 
			
		||||
	"119": "19",
 | 
			
		||||
	"276": "20",
 | 
			
		||||
	"918": "21",
 | 
			
		||||
	"362": "22",
 | 
			
		||||
	"400": "23",
 | 
			
		||||
	"611": "24",
 | 
			
		||||
	"94":  "25",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CweTopTwentyfiveURLs has CWE Top25 links
 | 
			
		||||
var CweTopTwentyfiveURLs = map[string]string{
 | 
			
		||||
	"2019": "https://cwe.mitre.org/top25/archive/2019/2019_cwe_top25.html",
 | 
			
		||||
	"2020": "https://cwe.mitre.org/top25/archive/2020/2020_cwe_top25.html",
 | 
			
		||||
	"2021": "https://cwe.mitre.org/top25/archive/2021/2021_cwe_top25.html",
 | 
			
		||||
	"2022": "https://cwe.mitre.org/top25/archive/2022/2022_cwe_top25.html",
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -261,21 +261,23 @@ func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf c
 | 
			
		||||
 | 
			
		||||
// isPkgCvesDetactable checks whether CVEs is detactable with gost and oval from the result
 | 
			
		||||
func isPkgCvesDetactable(r *models.ScanResult) bool {
 | 
			
		||||
	if r.Release == "" {
 | 
			
		||||
		logging.Log.Infof("r.Release is empty. Skip OVAL and gost detection")
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r.ScannedVia == "trivy" {
 | 
			
		||||
		logging.Log.Infof("r.ScannedVia is trivy. Skip OVAL and gost detection")
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch r.Family {
 | 
			
		||||
	case constant.FreeBSD, constant.ServerTypePseudo:
 | 
			
		||||
		logging.Log.Infof("%s type. Skip OVAL and gost detection", r.Family)
 | 
			
		||||
		return false
 | 
			
		||||
	case constant.Windows:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		if r.ScannedVia == "trivy" {
 | 
			
		||||
			logging.Log.Infof("r.ScannedVia is trivy. Skip OVAL and gost detection")
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if r.Release == "" {
 | 
			
		||||
			logging.Log.Infof("r.Release is empty. Skip OVAL and gost detection")
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(r.Packages)+len(r.SrcPackages) == 0 {
 | 
			
		||||
			logging.Log.Infof("Number of packages is 0. Skip OVAL and gost detection")
 | 
			
		||||
			return false
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ func DetectGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string,
 | 
			
		||||
	// TODO Use `https://github.com/shurcooL/githubv4` if the tool supports vulnerabilityAlerts Endpoint
 | 
			
		||||
	// Memo : https://developer.github.com/v4/explorer/
 | 
			
		||||
	const jsonfmt = `{"query":
 | 
			
		||||
	"query { repository(owner:\"%s\", name:\"%s\") { url vulnerabilityAlerts(first: %d, %s) { pageInfo { endCursor hasNextPage startCursor } edges { node { id dismissReason dismissedAt securityVulnerability{ package { name ecosystem } severity vulnerableVersionRange firstPatchedVersion { identifier } } securityAdvisory { description ghsaId permalink publishedAt summary updatedAt withdrawnAt origin severity references { url } identifiers { type value } } } } } } } "}`
 | 
			
		||||
	"query { repository(owner:\"%s\", name:\"%s\") { url vulnerabilityAlerts(first: %d, states:[OPEN], %s) { pageInfo { endCursor hasNextPage startCursor } edges { node { id dismissReason dismissedAt securityVulnerability{ package { name ecosystem } severity vulnerableVersionRange firstPatchedVersion { identifier } } securityAdvisory { description ghsaId permalink publishedAt summary updatedAt withdrawnAt origin severity references { url } identifiers { type value } } } } } } } "}`
 | 
			
		||||
	after := ""
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ func DetectLibsCves(r *models.ScanResult, cacheDir string, noProgress bool) (err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func downloadDB(appVersion, cacheDir string, quiet, skipUpdate bool) error {
 | 
			
		||||
	client := db.NewClient(cacheDir, quiet)
 | 
			
		||||
	client := db.NewClient(cacheDir, quiet, false)
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	needsUpdate, err := client.NeedsUpdate(appVersion, skipUpdate)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								go.mod
									
									
									
									
									
								
							@@ -3,67 +3,72 @@ module github.com/future-architect/vuls
 | 
			
		||||
go 1.18
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/Azure/azure-sdk-for-go v63.0.0+incompatible
 | 
			
		||||
	github.com/BurntSushi/toml v1.1.0
 | 
			
		||||
	github.com/Azure/azure-sdk-for-go v66.0.0+incompatible
 | 
			
		||||
	github.com/BurntSushi/toml v1.2.0
 | 
			
		||||
	github.com/CycloneDX/cyclonedx-go v0.7.0
 | 
			
		||||
	github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f
 | 
			
		||||
	github.com/aquasecurity/fanal v0.0.0-20220426115253-1d75fc0c7219
 | 
			
		||||
	github.com/aquasecurity/go-dep-parser v0.0.0-20220422134844-880747206031
 | 
			
		||||
	github.com/aquasecurity/trivy v0.27.1
 | 
			
		||||
	github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2
 | 
			
		||||
	github.com/aquasecurity/go-dep-parser v0.0.0-20221024082335-60502daef4ba
 | 
			
		||||
	github.com/aquasecurity/trivy v0.33.0
 | 
			
		||||
	github.com/aquasecurity/trivy-db v0.0.0-20220627104749-930461748b63
 | 
			
		||||
	github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
 | 
			
		||||
	github.com/aws/aws-sdk-go v1.43.31
 | 
			
		||||
	github.com/aws/aws-sdk-go v1.44.114
 | 
			
		||||
	github.com/c-robinson/iplib v1.0.3
 | 
			
		||||
	github.com/cenkalti/backoff v2.2.1+incompatible
 | 
			
		||||
	github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
 | 
			
		||||
	github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
 | 
			
		||||
	github.com/emersion/go-smtp v0.14.0
 | 
			
		||||
	github.com/google/subcommands v1.2.0
 | 
			
		||||
	github.com/google/uuid v1.3.0
 | 
			
		||||
	github.com/gosuri/uitable v0.0.4
 | 
			
		||||
	github.com/hashicorp/go-uuid v1.0.2
 | 
			
		||||
	github.com/hashicorp/go-uuid v1.0.3
 | 
			
		||||
	github.com/hashicorp/go-version v1.6.0
 | 
			
		||||
	github.com/jesseduffield/gocui v0.3.0
 | 
			
		||||
	github.com/k0kubun/pp v3.0.1+incompatible
 | 
			
		||||
	github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
 | 
			
		||||
	github.com/knqyf263/go-cpe v0.0.0-20201213041631-54f6ab28673f
 | 
			
		||||
	github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
 | 
			
		||||
	github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
 | 
			
		||||
	github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075
 | 
			
		||||
	github.com/kotakanbe/go-pingscanner v0.1.0
 | 
			
		||||
	github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
 | 
			
		||||
	github.com/mitchellh/go-homedir v1.1.0
 | 
			
		||||
	github.com/nlopes/slack v0.6.0
 | 
			
		||||
	github.com/olekukonko/tablewriter v0.0.5
 | 
			
		||||
	github.com/package-url/packageurl-go v0.1.1-0.20220203205134-d70459300c8a
 | 
			
		||||
	github.com/parnurzeal/gorequest v0.2.16
 | 
			
		||||
	github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
 | 
			
		||||
	github.com/sirupsen/logrus v1.8.1
 | 
			
		||||
	github.com/spf13/cobra v1.5.0
 | 
			
		||||
	github.com/sirupsen/logrus v1.9.0
 | 
			
		||||
	github.com/spf13/cobra v1.6.0
 | 
			
		||||
	github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86
 | 
			
		||||
	github.com/vulsio/go-cve-dictionary v0.8.2-0.20211028094424-0a854f8e8f85
 | 
			
		||||
	github.com/vulsio/go-cve-dictionary v0.8.2
 | 
			
		||||
	github.com/vulsio/go-exploitdb v0.4.2
 | 
			
		||||
	github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f
 | 
			
		||||
	github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14
 | 
			
		||||
	github.com/vulsio/gost v0.4.2-0.20220630181607-2ed593791ec3
 | 
			
		||||
	github.com/vulsio/goval-dictionary v0.7.3
 | 
			
		||||
	github.com/vulsio/goval-dictionary v0.8.0
 | 
			
		||||
	go.etcd.io/bbolt v1.3.6
 | 
			
		||||
	golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
 | 
			
		||||
	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
 | 
			
		||||
	golang.org/x/exp v0.0.0-20220823124025-807a23277127
 | 
			
		||||
	golang.org/x/oauth2 v0.1.0
 | 
			
		||||
	golang.org/x/sync v0.1.0
 | 
			
		||||
	golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	cloud.google.com/go v0.100.2 // indirect
 | 
			
		||||
	cloud.google.com/go/compute v1.6.1 // indirect
 | 
			
		||||
	cloud.google.com/go v0.103.0 // indirect
 | 
			
		||||
	cloud.google.com/go/compute v1.10.0 // indirect
 | 
			
		||||
	cloud.google.com/go/iam v0.3.0 // indirect
 | 
			
		||||
	cloud.google.com/go/storage v1.14.0 // indirect
 | 
			
		||||
	cloud.google.com/go/storage v1.23.0 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/autorest v0.11.25 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/autorest v0.11.28 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/logger v0.2.1 // indirect
 | 
			
		||||
	github.com/Azure/go-autorest/tracing v0.6.0 // indirect
 | 
			
		||||
	github.com/Microsoft/go-winio v0.6.0 // indirect
 | 
			
		||||
	github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
 | 
			
		||||
	github.com/PuerkitoBio/goquery v1.6.1 // indirect
 | 
			
		||||
	github.com/VividCortex/ewma v1.2.0 // indirect
 | 
			
		||||
	github.com/acomagu/bufpipe v1.0.3 // indirect
 | 
			
		||||
	github.com/andybalholm/cascadia v1.2.0 // indirect
 | 
			
		||||
	github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce // indirect
 | 
			
		||||
	github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 // indirect
 | 
			
		||||
@@ -71,17 +76,25 @@ require (
 | 
			
		||||
	github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
 | 
			
		||||
	github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
 | 
			
		||||
	github.com/briandowns/spinner v1.18.1 // indirect
 | 
			
		||||
	github.com/caarlos0/env/v6 v6.9.1 // indirect
 | 
			
		||||
	github.com/caarlos0/env/v6 v6.10.1 // indirect
 | 
			
		||||
	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 | 
			
		||||
	github.com/cheggaaa/pb/v3 v3.0.8 // indirect
 | 
			
		||||
	github.com/cheggaaa/pb/v3 v3.1.0 // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
			
		||||
	github.com/dgryski/go-minhash v0.0.0-20170608043002-7fe510aff544 // indirect
 | 
			
		||||
	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 | 
			
		||||
	github.com/docker/cli v20.10.12+incompatible // indirect
 | 
			
		||||
	github.com/docker/distribution v2.7.1+incompatible // indirect
 | 
			
		||||
	github.com/docker/docker v20.10.14+incompatible // indirect
 | 
			
		||||
	github.com/docker/docker-credential-helpers v0.6.4 // indirect
 | 
			
		||||
	github.com/dnaeon/go-vcr v1.2.0 // indirect
 | 
			
		||||
	github.com/docker/cli v20.10.20+incompatible // indirect
 | 
			
		||||
	github.com/docker/distribution v2.8.1+incompatible // indirect
 | 
			
		||||
	github.com/docker/docker v20.10.20+incompatible // indirect
 | 
			
		||||
	github.com/docker/docker-credential-helpers v0.7.0 // indirect
 | 
			
		||||
	github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1 // indirect
 | 
			
		||||
	github.com/emirpasic/gods v1.12.0 // indirect
 | 
			
		||||
	github.com/fatih/color v1.13.0 // indirect
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.5.4 // indirect
 | 
			
		||||
	github.com/go-enry/go-license-detector/v4 v4.3.0 // indirect
 | 
			
		||||
	github.com/go-git/gcfg v1.5.0 // indirect
 | 
			
		||||
	github.com/go-git/go-billy/v5 v5.3.1 // indirect
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.4.2 // indirect
 | 
			
		||||
	github.com/go-redis/redis/v8 v8.11.5 // indirect
 | 
			
		||||
	github.com/go-sql-driver/mysql v1.6.0 // indirect
 | 
			
		||||
	github.com/go-stack/stack v1.8.1 // indirect
 | 
			
		||||
@@ -89,18 +102,24 @@ require (
 | 
			
		||||
	github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
 | 
			
		||||
	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 | 
			
		||||
	github.com/golang/protobuf v1.5.2 // indirect
 | 
			
		||||
	github.com/google/go-containerregistry v0.8.0 // indirect
 | 
			
		||||
	github.com/googleapis/gax-go/v2 v2.4.0 // indirect
 | 
			
		||||
	github.com/google/go-cmp v0.5.9 // indirect
 | 
			
		||||
	github.com/google/go-containerregistry v0.12.0 // indirect
 | 
			
		||||
	github.com/google/licenseclassifier/v2 v2.0.0-pre6 // indirect
 | 
			
		||||
	github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
 | 
			
		||||
	github.com/googleapis/gax-go/v2 v2.5.1 // indirect
 | 
			
		||||
	github.com/googleapis/go-type-adapters v1.0.0 // indirect
 | 
			
		||||
	github.com/gorilla/websocket v1.4.2 // indirect
 | 
			
		||||
	github.com/hashicorp/errwrap v1.1.0 // indirect
 | 
			
		||||
	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 | 
			
		||||
	github.com/hashicorp/go-getter v1.5.11 // indirect
 | 
			
		||||
	github.com/hashicorp/go-getter v1.6.2 // indirect
 | 
			
		||||
	github.com/hashicorp/go-multierror v1.1.1 // indirect
 | 
			
		||||
	github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
 | 
			
		||||
	github.com/hashicorp/go-safetemp v1.0.0 // indirect
 | 
			
		||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
			
		||||
	github.com/hhatto/gorst v0.0.0-20181029133204-ca9f730cac5b // indirect
 | 
			
		||||
	github.com/imdario/mergo v0.3.13 // indirect
 | 
			
		||||
	github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect
 | 
			
		||||
	github.com/inconshreveable/mousetrap v1.0.0 // indirect
 | 
			
		||||
	github.com/inconshreveable/mousetrap v1.0.1 // indirect
 | 
			
		||||
	github.com/jackc/chunkreader/v2 v2.0.1 // indirect
 | 
			
		||||
	github.com/jackc/pgconn v1.12.1 // indirect
 | 
			
		||||
	github.com/jackc/pgio v1.0.0 // indirect
 | 
			
		||||
@@ -109,11 +128,14 @@ require (
 | 
			
		||||
	github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
 | 
			
		||||
	github.com/jackc/pgtype v1.11.0 // indirect
 | 
			
		||||
	github.com/jackc/pgx/v4 v4.16.1 // indirect
 | 
			
		||||
	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
 | 
			
		||||
	github.com/jdkato/prose v1.1.0 // indirect
 | 
			
		||||
	github.com/jinzhu/inflection v1.0.0 // indirect
 | 
			
		||||
	github.com/jinzhu/now v1.1.5 // indirect
 | 
			
		||||
	github.com/jmespath/go-jmespath v0.4.0 // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.14.2 // indirect
 | 
			
		||||
	github.com/lib/pq v1.10.5 // indirect
 | 
			
		||||
	github.com/kevinburke/ssh_config v1.1.0 // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.15.11 // indirect
 | 
			
		||||
	github.com/liamg/jfather v0.0.7 // indirect
 | 
			
		||||
	github.com/magiconair/properties v1.8.6 // indirect
 | 
			
		||||
	github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
 | 
			
		||||
	github.com/mattn/go-colorable v0.1.12 // indirect
 | 
			
		||||
@@ -123,47 +145,62 @@ require (
 | 
			
		||||
	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 | 
			
		||||
	github.com/mitchellh/go-testing-interface v1.0.0 // indirect
 | 
			
		||||
	github.com/mitchellh/mapstructure v1.5.0 // indirect
 | 
			
		||||
	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
 | 
			
		||||
	github.com/nsf/termbox-go v1.1.1 // indirect
 | 
			
		||||
	github.com/opencontainers/go-digest v1.0.0 // indirect
 | 
			
		||||
	github.com/opencontainers/image-spec v1.0.2 // indirect
 | 
			
		||||
	github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml v1.9.5 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml/v2 v2.0.2 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml/v2 v2.0.5 // indirect
 | 
			
		||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.2.0 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.3.1 // indirect
 | 
			
		||||
	github.com/rogpeppe/go-internal v1.8.1 // indirect
 | 
			
		||||
	github.com/spf13/afero v1.8.2 // indirect
 | 
			
		||||
	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 | 
			
		||||
	github.com/samber/lo v1.28.2 // indirect
 | 
			
		||||
	github.com/sergi/go-diff v1.2.0 // indirect
 | 
			
		||||
	github.com/shogo82148/go-shuffle v0.0.0-20170808115208-59829097ff3b // indirect
 | 
			
		||||
	github.com/spdx/tools-golang v0.3.0 // indirect
 | 
			
		||||
	github.com/spf13/afero v1.9.2 // indirect
 | 
			
		||||
	github.com/spf13/cast v1.5.0 // indirect
 | 
			
		||||
	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 | 
			
		||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
			
		||||
	github.com/spf13/viper v1.12.0 // indirect
 | 
			
		||||
	github.com/stretchr/objx v0.3.0 // indirect
 | 
			
		||||
	github.com/stretchr/testify v1.7.2 // indirect
 | 
			
		||||
	github.com/subosito/gotenv v1.4.0 // indirect
 | 
			
		||||
	github.com/spf13/viper v1.13.0 // indirect
 | 
			
		||||
	github.com/stretchr/objx v0.4.0 // indirect
 | 
			
		||||
	github.com/stretchr/testify v1.8.0 // indirect
 | 
			
		||||
	github.com/subosito/gotenv v1.4.1 // indirect
 | 
			
		||||
	github.com/ulikunitz/xz v0.5.10 // indirect
 | 
			
		||||
	github.com/xanzy/ssh-agent v0.3.0 // indirect
 | 
			
		||||
	go.opencensus.io v0.23.0 // indirect
 | 
			
		||||
	go.uber.org/atomic v1.7.0 // indirect
 | 
			
		||||
	go.uber.org/atomic v1.9.0 // indirect
 | 
			
		||||
	go.uber.org/goleak v1.1.12 // indirect
 | 
			
		||||
	go.uber.org/multierr v1.6.0 // indirect
 | 
			
		||||
	go.uber.org/zap v1.21.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
 | 
			
		||||
	golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
 | 
			
		||||
	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 | 
			
		||||
	golang.org/x/text v0.3.7 // indirect
 | 
			
		||||
	google.golang.org/api v0.81.0 // indirect
 | 
			
		||||
	go.uber.org/multierr v1.8.0 // indirect
 | 
			
		||||
	go.uber.org/zap v1.23.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/mod v0.6.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/term v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.4.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
 | 
			
		||||
	golang.org/x/tools v0.2.0 // indirect
 | 
			
		||||
	gonum.org/v1/gonum v0.7.0 // indirect
 | 
			
		||||
	google.golang.org/api v0.98.0 // indirect
 | 
			
		||||
	google.golang.org/appengine v1.6.7 // indirect
 | 
			
		||||
	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
 | 
			
		||||
	google.golang.org/grpc v1.46.2 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.28.0 // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.66.6 // indirect
 | 
			
		||||
	google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 // indirect
 | 
			
		||||
	google.golang.org/grpc v1.50.1 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.28.1 // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.67.0 // indirect
 | 
			
		||||
	gopkg.in/neurosnap/sentences.v1 v1.0.6 // indirect
 | 
			
		||||
	gopkg.in/warnings.v0 v0.1.2 // indirect
 | 
			
		||||
	gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
			
		||||
	gorm.io/driver/mysql v1.3.4 // indirect
 | 
			
		||||
	gorm.io/driver/postgres v1.3.7 // indirect
 | 
			
		||||
	gorm.io/driver/sqlite v1.3.4 // indirect
 | 
			
		||||
	gorm.io/gorm v1.23.5 // indirect
 | 
			
		||||
	k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect
 | 
			
		||||
	gorm.io/driver/mysql v1.3.5 // indirect
 | 
			
		||||
	gorm.io/driver/postgres v1.3.8 // indirect
 | 
			
		||||
	gorm.io/driver/sqlite v1.3.6 // indirect
 | 
			
		||||
	gorm.io/gorm v1.23.8 // indirect
 | 
			
		||||
	k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
 | 
			
		||||
	moul.io/http2curl v1.0.0 // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// See https://github.com/moby/moby/issues/42939#issuecomment-1114255529
 | 
			
		||||
replace github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220224222438-c78f6963a1c0+incompatible
 | 
			
		||||
 
 | 
			
		||||
@@ -130,19 +130,23 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
 | 
			
		||||
 | 
			
		||||
	for cveID, cve := range cves {
 | 
			
		||||
		cveCont, mitigations := ms.ConvertToModel(&cve)
 | 
			
		||||
		advisories := []models.DistroAdvisory{}
 | 
			
		||||
		uniqKB := map[string]struct{}{}
 | 
			
		||||
		for _, p := range cve.Products {
 | 
			
		||||
			for _, kb := range p.KBs {
 | 
			
		||||
				adv := models.DistroAdvisory{
 | 
			
		||||
					AdvisoryID:  kb.Article,
 | 
			
		||||
					Description: "Microsoft Knowledge Base",
 | 
			
		||||
				}
 | 
			
		||||
				if _, err := strconv.Atoi(kb.Article); err == nil {
 | 
			
		||||
					adv.AdvisoryID = fmt.Sprintf("KB%s", kb.Article)
 | 
			
		||||
					uniqKB[fmt.Sprintf("KB%s", kb.Article)] = struct{}{}
 | 
			
		||||
				} else {
 | 
			
		||||
					uniqKB[kb.Article] = struct{}{}
 | 
			
		||||
				}
 | 
			
		||||
				advisories = append(advisories, adv)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		advisories := []models.DistroAdvisory{}
 | 
			
		||||
		for kb := range uniqKB {
 | 
			
		||||
			advisories = append(advisories, models.DistroAdvisory{
 | 
			
		||||
				AdvisoryID:  kb,
 | 
			
		||||
				Description: "Microsoft Knowledge Base",
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		r.ScannedCves[cveID] = models.VulnInfo{
 | 
			
		||||
			CveID:            cveID,
 | 
			
		||||
 
 | 
			
		||||
 Submodule integration updated: d97bf53114...b40375c4df
									
								
							@@ -1,12 +1,10 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	ftypes "github.com/aquasecurity/fanal/types"
 | 
			
		||||
	"github.com/aquasecurity/trivy-db/pkg/db"
 | 
			
		||||
	trivyDBTypes "github.com/aquasecurity/trivy-db/pkg/types"
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/detector/library"
 | 
			
		||||
	ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/types"
 | 
			
		||||
	"golang.org/x/xerrors"
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +63,7 @@ func (s LibraryScanner) Scan() ([]VulnInfo, error) {
 | 
			
		||||
	}
 | 
			
		||||
	var vulnerabilities = []VulnInfo{}
 | 
			
		||||
	for _, pkg := range s.Libs {
 | 
			
		||||
		tvulns, err := scanner.DetectVulnerabilities(pkg.Name, pkg.Version)
 | 
			
		||||
		tvulns, err := scanner.DetectVulnerabilities("", pkg.Name, pkg.Version)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, xerrors.Errorf("failed to detect %s vulnerabilities: %w", scanner.Type(), err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -131,25 +129,24 @@ func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[
 | 
			
		||||
	return contents
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LibraryMap is filename and library type
 | 
			
		||||
var LibraryMap = map[string]string{
 | 
			
		||||
	ftypes.NpmPkgLock:      "node",
 | 
			
		||||
	ftypes.YarnLock:        "node",
 | 
			
		||||
	ftypes.GemfileLock:     "ruby",
 | 
			
		||||
	ftypes.CargoLock:       "rust",
 | 
			
		||||
	ftypes.ComposerLock:    "php",
 | 
			
		||||
	ftypes.PipRequirements: "python",
 | 
			
		||||
	ftypes.PipfileLock:     "python",
 | 
			
		||||
	ftypes.PoetryLock:      "python",
 | 
			
		||||
	ftypes.NuGetPkgsLock:   ".net",
 | 
			
		||||
	ftypes.NuGetPkgsConfig: ".net",
 | 
			
		||||
	ftypes.GoMod:           "gomod",
 | 
			
		||||
	ftypes.GoSum:           "gomod",
 | 
			
		||||
	ftypes.MavenPom:        "java",
 | 
			
		||||
	"*.jar":                "java",
 | 
			
		||||
	"*.war":                "java",
 | 
			
		||||
	"*.ear":                "java",
 | 
			
		||||
	"*.par":                "java",
 | 
			
		||||
// FindLockFiles is a list of filenames that is the target of findLock
 | 
			
		||||
var FindLockFiles = []string{
 | 
			
		||||
	// node
 | 
			
		||||
	ftypes.NpmPkgLock, ftypes.YarnLock, ftypes.PnpmLock,
 | 
			
		||||
	// ruby
 | 
			
		||||
	ftypes.GemfileLock,
 | 
			
		||||
	// rust
 | 
			
		||||
	ftypes.CargoLock,
 | 
			
		||||
	// php
 | 
			
		||||
	ftypes.ComposerLock,
 | 
			
		||||
	// python
 | 
			
		||||
	ftypes.PipRequirements, ftypes.PipfileLock, ftypes.PoetryLock,
 | 
			
		||||
	// .net
 | 
			
		||||
	ftypes.NuGetPkgsLock, ftypes.NuGetPkgsConfig, "*.deps.json",
 | 
			
		||||
	// gomod
 | 
			
		||||
	ftypes.GoMod, ftypes.GoSum,
 | 
			
		||||
	// java
 | 
			
		||||
	ftypes.MavenPom, "*.jar", "*.war", "*.ear", "*.par",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLibraryKey returns target library key
 | 
			
		||||
@@ -165,20 +162,14 @@ func (s LibraryScanner) GetLibraryKey() string {
 | 
			
		||||
		return "gomod"
 | 
			
		||||
	case ftypes.Jar, ftypes.Pom:
 | 
			
		||||
		return "java"
 | 
			
		||||
	case ftypes.Npm, ftypes.Yarn, ftypes.NodePkg, ftypes.JavaScript:
 | 
			
		||||
	case ftypes.Npm, ftypes.Yarn, ftypes.Pnpm, ftypes.NodePkg, ftypes.JavaScript:
 | 
			
		||||
		return "node"
 | 
			
		||||
	case ftypes.NuGet:
 | 
			
		||||
	case ftypes.NuGet, ftypes.DotNetCore:
 | 
			
		||||
		return ".net"
 | 
			
		||||
	case ftypes.Pipenv, ftypes.Poetry, ftypes.Pip, ftypes.PythonPkg:
 | 
			
		||||
		return "python"
 | 
			
		||||
	default:
 | 
			
		||||
		filename := filepath.Base(s.LockfilePath)
 | 
			
		||||
		switch filepath.Ext(filename) {
 | 
			
		||||
		case ".jar", ".war", ".ear", ".par":
 | 
			
		||||
			return "java"
 | 
			
		||||
		default:
 | 
			
		||||
			return LibraryMap[filename]
 | 
			
		||||
		}
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								oval/util.go
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								oval/util.go
									
									
									
									
									
								
							@@ -93,6 +93,7 @@ type request struct {
 | 
			
		||||
	binaryPackNames   []string
 | 
			
		||||
	isSrcPack         bool
 | 
			
		||||
	modularityLabel   string // RHEL 8 or later only
 | 
			
		||||
	repository        string // Amazon Linux 2 Only
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type response struct {
 | 
			
		||||
@@ -102,6 +103,25 @@ type response struct {
 | 
			
		||||
 | 
			
		||||
// getDefsByPackNameViaHTTP fetches OVAL information via HTTP
 | 
			
		||||
func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ovalResult, err error) {
 | 
			
		||||
	ovalFamily, err := GetFamilyInOval(r.Family)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return relatedDefs, xerrors.Errorf("Failed to GetFamilyInOval. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	ovalRelease := r.Release
 | 
			
		||||
	switch r.Family {
 | 
			
		||||
	case constant.CentOS:
 | 
			
		||||
		ovalRelease = strings.TrimPrefix(r.Release, "stream")
 | 
			
		||||
	case constant.Amazon:
 | 
			
		||||
		switch strings.Fields(r.Release)[0] {
 | 
			
		||||
		case "2022":
 | 
			
		||||
			ovalRelease = "2022"
 | 
			
		||||
		case "2":
 | 
			
		||||
			ovalRelease = "2"
 | 
			
		||||
		default:
 | 
			
		||||
			ovalRelease = "1"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nReq := len(r.Packages) + len(r.SrcPackages)
 | 
			
		||||
	reqChan := make(chan request, nReq)
 | 
			
		||||
	resChan := make(chan response, nReq)
 | 
			
		||||
@@ -112,13 +132,18 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ova
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		for _, pack := range r.Packages {
 | 
			
		||||
			reqChan <- request{
 | 
			
		||||
			req := request{
 | 
			
		||||
				packName:          pack.Name,
 | 
			
		||||
				versionRelease:    pack.FormatVer(),
 | 
			
		||||
				newVersionRelease: pack.FormatVer(),
 | 
			
		||||
				newVersionRelease: pack.FormatNewVer(),
 | 
			
		||||
				isSrcPack:         false,
 | 
			
		||||
				arch:              pack.Arch,
 | 
			
		||||
				repository:        pack.Repository,
 | 
			
		||||
			}
 | 
			
		||||
			if ovalFamily == constant.Amazon && ovalRelease == "2" && req.repository == "" {
 | 
			
		||||
				req.repository = "amzn2-core"
 | 
			
		||||
			}
 | 
			
		||||
			reqChan <- req
 | 
			
		||||
		}
 | 
			
		||||
		for _, pack := range r.SrcPackages {
 | 
			
		||||
			reqChan <- request{
 | 
			
		||||
@@ -131,14 +156,6 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ova
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	ovalFamily, err := GetFamilyInOval(r.Family)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return relatedDefs, xerrors.Errorf("Failed to GetFamilyInOval. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	ovalRelease := r.Release
 | 
			
		||||
	if r.Family == constant.CentOS {
 | 
			
		||||
		ovalRelease = strings.TrimPrefix(r.Release, "stream")
 | 
			
		||||
	}
 | 
			
		||||
	concurrency := 10
 | 
			
		||||
	tasks := util.GenWorkers(concurrency)
 | 
			
		||||
	for i := 0; i < nReq; i++ {
 | 
			
		||||
@@ -168,7 +185,7 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ova
 | 
			
		||||
		select {
 | 
			
		||||
		case res := <-resChan:
 | 
			
		||||
			for _, def := range res.defs {
 | 
			
		||||
				affected, notFixedYet, fixedIn, err := isOvalDefAffected(def, res.request, ovalFamily, r.RunningKernel, r.EnabledDnfModules)
 | 
			
		||||
				affected, notFixedYet, fixedIn, err := isOvalDefAffected(def, res.request, ovalFamily, ovalRelease, r.RunningKernel, r.EnabledDnfModules)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					errs = append(errs, err)
 | 
			
		||||
					continue
 | 
			
		||||
@@ -248,15 +265,39 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getDefsByPackNameFromOvalDB(r *models.ScanResult, driver ovaldb.DB) (relatedDefs ovalResult, err error) {
 | 
			
		||||
	ovalFamily, err := GetFamilyInOval(r.Family)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return relatedDefs, xerrors.Errorf("Failed to GetFamilyInOval. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	ovalRelease := r.Release
 | 
			
		||||
	switch r.Family {
 | 
			
		||||
	case constant.CentOS:
 | 
			
		||||
		ovalRelease = strings.TrimPrefix(r.Release, "stream")
 | 
			
		||||
	case constant.Amazon:
 | 
			
		||||
		switch strings.Fields(r.Release)[0] {
 | 
			
		||||
		case "2022":
 | 
			
		||||
			ovalRelease = "2022"
 | 
			
		||||
		case "2":
 | 
			
		||||
			ovalRelease = "2"
 | 
			
		||||
		default:
 | 
			
		||||
			ovalRelease = "1"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	requests := []request{}
 | 
			
		||||
	for _, pack := range r.Packages {
 | 
			
		||||
		requests = append(requests, request{
 | 
			
		||||
		req := request{
 | 
			
		||||
			packName:          pack.Name,
 | 
			
		||||
			versionRelease:    pack.FormatVer(),
 | 
			
		||||
			newVersionRelease: pack.FormatNewVer(),
 | 
			
		||||
			arch:              pack.Arch,
 | 
			
		||||
			repository:        pack.Repository,
 | 
			
		||||
			isSrcPack:         false,
 | 
			
		||||
		})
 | 
			
		||||
		}
 | 
			
		||||
		if ovalFamily == constant.Amazon && ovalRelease == "2" && req.repository == "" {
 | 
			
		||||
			req.repository = "amzn2-core"
 | 
			
		||||
		}
 | 
			
		||||
		requests = append(requests, req)
 | 
			
		||||
	}
 | 
			
		||||
	for _, pack := range r.SrcPackages {
 | 
			
		||||
		requests = append(requests, request{
 | 
			
		||||
@@ -267,22 +308,13 @@ func getDefsByPackNameFromOvalDB(r *models.ScanResult, driver ovaldb.DB) (relate
 | 
			
		||||
			isSrcPack:       true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ovalFamily, err := GetFamilyInOval(r.Family)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return relatedDefs, xerrors.Errorf("Failed to GetFamilyInOval. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	ovalRelease := r.Release
 | 
			
		||||
	if r.Family == constant.CentOS {
 | 
			
		||||
		ovalRelease = strings.TrimPrefix(r.Release, "stream")
 | 
			
		||||
	}
 | 
			
		||||
	for _, req := range requests {
 | 
			
		||||
		definitions, err := driver.GetByPackName(ovalFamily, ovalRelease, req.packName, req.arch)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return relatedDefs, xerrors.Errorf("Failed to get %s OVAL info by package: %#v, err: %w", r.Family, req, err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, def := range definitions {
 | 
			
		||||
			affected, notFixedYet, fixedIn, err := isOvalDefAffected(def, req, ovalFamily, r.RunningKernel, r.EnabledDnfModules)
 | 
			
		||||
			affected, notFixedYet, fixedIn, err := isOvalDefAffected(def, req, ovalFamily, ovalRelease, r.RunningKernel, r.EnabledDnfModules)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return relatedDefs, xerrors.Errorf("Failed to exec isOvalAffected. err: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
@@ -314,7 +346,16 @@ func getDefsByPackNameFromOvalDB(r *models.ScanResult, driver ovaldb.DB) (relate
 | 
			
		||||
 | 
			
		||||
var modularVersionPattern = regexp.MustCompile(`.+\.module(?:\+el|_f)\d{1,2}.*`)
 | 
			
		||||
 | 
			
		||||
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel, enabledMods []string) (affected, notFixedYet bool, fixedIn string, err error) {
 | 
			
		||||
func isOvalDefAffected(def ovalmodels.Definition, req request, family, release string, running models.Kernel, enabledMods []string) (affected, notFixedYet bool, fixedIn string, err error) {
 | 
			
		||||
	if family == constant.Amazon && release == "2" {
 | 
			
		||||
		if def.Advisory.AffectedRepository == "" {
 | 
			
		||||
			def.Advisory.AffectedRepository = "amzn2-core"
 | 
			
		||||
		}
 | 
			
		||||
		if req.repository != def.Advisory.AffectedRepository {
 | 
			
		||||
			return false, false, "", nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, ovalPack := range def.AffectedPacks {
 | 
			
		||||
		if req.packName != ovalPack.Name {
 | 
			
		||||
			continue
 | 
			
		||||
 
 | 
			
		||||
@@ -199,11 +199,12 @@ func TestDefpacksToPackStatuses(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestIsOvalDefAffected(t *testing.T) {
 | 
			
		||||
	type in struct {
 | 
			
		||||
		def    ovalmodels.Definition
 | 
			
		||||
		req    request
 | 
			
		||||
		family string
 | 
			
		||||
		kernel models.Kernel
 | 
			
		||||
		mods   []string
 | 
			
		||||
		def     ovalmodels.Definition
 | 
			
		||||
		req     request
 | 
			
		||||
		family  string
 | 
			
		||||
		release string
 | 
			
		||||
		kernel  models.Kernel
 | 
			
		||||
		mods    []string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in          in
 | 
			
		||||
@@ -1856,10 +1857,63 @@ func TestIsOvalDefAffected(t *testing.T) {
 | 
			
		||||
			wantErr: false,
 | 
			
		||||
			fixedIn: "",
 | 
			
		||||
		},
 | 
			
		||||
		// amazon linux 2 repository
 | 
			
		||||
		{
 | 
			
		||||
			in: in{
 | 
			
		||||
				family:  constant.Amazon,
 | 
			
		||||
				release: "2",
 | 
			
		||||
				def: ovalmodels.Definition{
 | 
			
		||||
					Advisory: ovalmodels.Advisory{
 | 
			
		||||
						AffectedRepository: "amzn2-core",
 | 
			
		||||
					},
 | 
			
		||||
					AffectedPacks: []ovalmodels.Package{
 | 
			
		||||
						{
 | 
			
		||||
							Name:    "nginx",
 | 
			
		||||
							Version: "2.17-106.0.1",
 | 
			
		||||
							Arch:    "x86_64",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				req: request{
 | 
			
		||||
					packName:       "nginx",
 | 
			
		||||
					versionRelease: "2.17-105.0.1",
 | 
			
		||||
					arch:           "x86_64",
 | 
			
		||||
					repository:     "amzn2-core",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			affected: true,
 | 
			
		||||
			fixedIn:  "2.17-106.0.1",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: in{
 | 
			
		||||
				family:  constant.Amazon,
 | 
			
		||||
				release: "2",
 | 
			
		||||
				def: ovalmodels.Definition{
 | 
			
		||||
					Advisory: ovalmodels.Advisory{
 | 
			
		||||
						AffectedRepository: "amzn2-core",
 | 
			
		||||
					},
 | 
			
		||||
					AffectedPacks: []ovalmodels.Package{
 | 
			
		||||
						{
 | 
			
		||||
							Name:    "nginx",
 | 
			
		||||
							Version: "2.17-106.0.1",
 | 
			
		||||
							Arch:    "x86_64",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				req: request{
 | 
			
		||||
					packName:       "nginx",
 | 
			
		||||
					versionRelease: "2.17-105.0.1",
 | 
			
		||||
					arch:           "x86_64",
 | 
			
		||||
					repository:     "amzn2extra-nginx",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			affected: false,
 | 
			
		||||
			fixedIn:  "",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, tt := range tests {
 | 
			
		||||
		affected, notFixedYet, fixedIn, err := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.kernel, tt.in.mods)
 | 
			
		||||
		affected, notFixedYet, fixedIn, err := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.release, tt.in.kernel, tt.in.mods)
 | 
			
		||||
		if tt.wantErr != (err != nil) {
 | 
			
		||||
			t.Errorf("[%d] err\nexpected: %t\n  actual: %s\n", i, tt.wantErr, err)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,24 +2,30 @@ package reporter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/CycloneDX/cyclonedx-go"
 | 
			
		||||
	"golang.org/x/xerrors"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/future-architect/vuls/reporter/sbom"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LocalFileWriter writes results to a local file.
 | 
			
		||||
type LocalFileWriter struct {
 | 
			
		||||
	CurrentDir        string
 | 
			
		||||
	DiffPlus          bool
 | 
			
		||||
	DiffMinus         bool
 | 
			
		||||
	FormatJSON        bool
 | 
			
		||||
	FormatCsv         bool
 | 
			
		||||
	FormatFullText    bool
 | 
			
		||||
	FormatOneLineText bool
 | 
			
		||||
	FormatList        bool
 | 
			
		||||
	Gzip              bool
 | 
			
		||||
	CurrentDir          string
 | 
			
		||||
	DiffPlus            bool
 | 
			
		||||
	DiffMinus           bool
 | 
			
		||||
	FormatJSON          bool
 | 
			
		||||
	FormatCsv           bool
 | 
			
		||||
	FormatFullText      bool
 | 
			
		||||
	FormatOneLineText   bool
 | 
			
		||||
	FormatList          bool
 | 
			
		||||
	FormatCycloneDXJSON bool
 | 
			
		||||
	FormatCycloneDXXML  bool
 | 
			
		||||
	Gzip                bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
 | 
			
		||||
@@ -86,6 +92,28 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if w.FormatCycloneDXJSON {
 | 
			
		||||
			bs, err := sbom.GenerateCycloneDX(cyclonedx.BOMFileFormatJSON, r)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return xerrors.Errorf("Failed to generate CycloneDX JSON. err: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			p := fmt.Sprintf("%s_cyclonedx.json", path)
 | 
			
		||||
			if err := w.writeFile(p, bs, 0600); err != nil {
 | 
			
		||||
				return xerrors.Errorf("Failed to write CycloneDX JSON. path: %s, err: %w", p, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if w.FormatCycloneDXXML {
 | 
			
		||||
			bs, err := sbom.GenerateCycloneDX(cyclonedx.BOMFileFormatXML, r)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return xerrors.Errorf("Failed to generate CycloneDX XML. err: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			p := fmt.Sprintf("%s_cyclonedx.xml", path)
 | 
			
		||||
			if err := w.writeFile(p, bs, 0600); err != nil {
 | 
			
		||||
				return xerrors.Errorf("Failed to write CycloneDX XML. path: %s, err: %w", p, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										510
									
								
								reporter/sbom/cyclonedx.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								reporter/sbom/cyclonedx.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,510 @@
 | 
			
		||||
package sbom
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	cdx "github.com/CycloneDX/cyclonedx-go"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"github.com/package-url/packageurl-go"
 | 
			
		||||
	"golang.org/x/exp/maps"
 | 
			
		||||
	"golang.org/x/xerrors"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/constant"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func GenerateCycloneDX(format cdx.BOMFileFormat, r models.ScanResult) ([]byte, error) {
 | 
			
		||||
	bom := cdx.NewBOM()
 | 
			
		||||
	bom.SerialNumber = uuid.New().URN()
 | 
			
		||||
	bom.Metadata = cdxMetadata(r)
 | 
			
		||||
	bom.Components, bom.Dependencies, bom.Vulnerabilities = cdxComponents(r, bom.Metadata.Component.BOMRef)
 | 
			
		||||
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	enc := cdx.NewBOMEncoder(buf, format)
 | 
			
		||||
	enc.SetPretty(true)
 | 
			
		||||
	if err := enc.Encode(bom); err != nil {
 | 
			
		||||
		return nil, xerrors.Errorf("Failed to encode CycloneDX. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return buf.Bytes(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxMetadata(result models.ScanResult) *cdx.Metadata {
 | 
			
		||||
	metadata := cdx.Metadata{
 | 
			
		||||
		Timestamp: result.ReportedAt.Format(time.RFC3339),
 | 
			
		||||
		Tools: &[]cdx.Tool{
 | 
			
		||||
			{
 | 
			
		||||
				Vendor:  "future-architect",
 | 
			
		||||
				Name:    "vuls",
 | 
			
		||||
				Version: fmt.Sprintf("%s-%s", result.ReportedVersion, result.ReportedRevision),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Component: &cdx.Component{
 | 
			
		||||
			BOMRef: uuid.NewString(),
 | 
			
		||||
			Type:   cdx.ComponentTypeOS,
 | 
			
		||||
			Name:   result.ServerName,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return &metadata
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxComponents(result models.ScanResult, metaBomRef string) (*[]cdx.Component, *[]cdx.Dependency, *[]cdx.Vulnerability) {
 | 
			
		||||
	var components []cdx.Component
 | 
			
		||||
	bomRefs := map[string][]string{}
 | 
			
		||||
 | 
			
		||||
	ospkgToPURL := map[string]string{}
 | 
			
		||||
	if ospkgComps := ospkgToCdxComponents(result.Family, result.Release, result.RunningKernel, result.Packages, result.SrcPackages, ospkgToPURL); ospkgComps != nil {
 | 
			
		||||
		bomRefs[metaBomRef] = append(bomRefs[metaBomRef], ospkgComps[0].BOMRef)
 | 
			
		||||
		for _, comp := range ospkgComps[1:] {
 | 
			
		||||
			bomRefs[ospkgComps[0].BOMRef] = append(bomRefs[ospkgComps[0].BOMRef], comp.BOMRef)
 | 
			
		||||
		}
 | 
			
		||||
		components = append(components, ospkgComps...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cpeComps := cpeToCdxComponents(result.ScannedCves); cpeComps != nil {
 | 
			
		||||
		bomRefs[metaBomRef] = append(bomRefs[metaBomRef], cpeComps[0].BOMRef)
 | 
			
		||||
		for _, comp := range cpeComps[1:] {
 | 
			
		||||
			bomRefs[cpeComps[0].BOMRef] = append(bomRefs[cpeComps[0].BOMRef], comp.BOMRef)
 | 
			
		||||
		}
 | 
			
		||||
		components = append(components, cpeComps...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	libpkgToPURL := map[string]map[string]string{}
 | 
			
		||||
	for _, libscanner := range result.LibraryScanners {
 | 
			
		||||
		libpkgToPURL[libscanner.LockfilePath] = map[string]string{}
 | 
			
		||||
 | 
			
		||||
		libpkgComps := libpkgToCdxComponents(libscanner, libpkgToPURL)
 | 
			
		||||
		bomRefs[metaBomRef] = append(bomRefs[metaBomRef], libpkgComps[0].BOMRef)
 | 
			
		||||
		for _, comp := range libpkgComps[1:] {
 | 
			
		||||
			bomRefs[libpkgComps[0].BOMRef] = append(bomRefs[libpkgComps[0].BOMRef], comp.BOMRef)
 | 
			
		||||
		}
 | 
			
		||||
		components = append(components, libpkgComps...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wppkgToPURL := map[string]string{}
 | 
			
		||||
	if wppkgComps := wppkgToCdxComponents(result.WordPressPackages, wppkgToPURL); wppkgComps != nil {
 | 
			
		||||
		bomRefs[metaBomRef] = append(bomRefs[metaBomRef], wppkgComps[0].BOMRef)
 | 
			
		||||
		for _, comp := range wppkgComps[1:] {
 | 
			
		||||
			bomRefs[wppkgComps[0].BOMRef] = append(bomRefs[wppkgComps[0].BOMRef], comp.BOMRef)
 | 
			
		||||
		}
 | 
			
		||||
		components = append(components, wppkgComps...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &components, cdxDependencies(bomRefs), cdxVulnerabilities(result, ospkgToPURL, libpkgToPURL, wppkgToPURL)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func osToCdxComponent(family, release, runningKernelRelease, runningKernelVersion string) cdx.Component {
 | 
			
		||||
	props := []cdx.Property{
 | 
			
		||||
		{
 | 
			
		||||
			Name:  "future-architect:vuls:Type",
 | 
			
		||||
			Value: "Package",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	if runningKernelRelease != "" {
 | 
			
		||||
		props = append(props, cdx.Property{
 | 
			
		||||
			Name:  "RunningKernelRelease",
 | 
			
		||||
			Value: runningKernelRelease,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if runningKernelVersion != "" {
 | 
			
		||||
		props = append(props, cdx.Property{
 | 
			
		||||
			Name:  "RunningKernelVersion",
 | 
			
		||||
			Value: runningKernelVersion,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return cdx.Component{
 | 
			
		||||
		BOMRef:     uuid.NewString(),
 | 
			
		||||
		Type:       cdx.ComponentTypeOS,
 | 
			
		||||
		Name:       family,
 | 
			
		||||
		Version:    release,
 | 
			
		||||
		Properties: &props,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ospkgToCdxComponents(family, release string, runningKernel models.Kernel, binpkgs models.Packages, srcpkgs models.SrcPackages, ospkgToPURL map[string]string) []cdx.Component {
 | 
			
		||||
	if family == "" {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	components := []cdx.Component{
 | 
			
		||||
		osToCdxComponent(family, release, runningKernel.Release, runningKernel.Version),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(binpkgs) == 0 {
 | 
			
		||||
		return components
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type srcpkg struct {
 | 
			
		||||
		name    string
 | 
			
		||||
		version string
 | 
			
		||||
		arch    string
 | 
			
		||||
	}
 | 
			
		||||
	binToSrc := map[string]srcpkg{}
 | 
			
		||||
	for _, pack := range srcpkgs {
 | 
			
		||||
		for _, binpkg := range pack.BinaryNames {
 | 
			
		||||
			binToSrc[binpkg] = srcpkg{
 | 
			
		||||
				name:    pack.Name,
 | 
			
		||||
				version: pack.Version,
 | 
			
		||||
				arch:    pack.Arch,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, pack := range binpkgs {
 | 
			
		||||
		var props []cdx.Property
 | 
			
		||||
		if p, ok := binToSrc[pack.Name]; ok {
 | 
			
		||||
			if p.name != "" {
 | 
			
		||||
				props = append(props, cdx.Property{
 | 
			
		||||
					Name:  "future-architect:vuls:SrcName",
 | 
			
		||||
					Value: p.name,
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
			if p.version != "" {
 | 
			
		||||
				props = append(props, cdx.Property{
 | 
			
		||||
					Name:  "future-architect:vuls:SrcVersion",
 | 
			
		||||
					Value: p.version,
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
			if p.arch != "" {
 | 
			
		||||
				props = append(props, cdx.Property{
 | 
			
		||||
					Name:  "future-architect:vuls:SrcArch",
 | 
			
		||||
					Value: p.arch,
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		purl := toPkgPURL(family, release, pack.Name, pack.Version, pack.Release, pack.Arch, pack.Repository)
 | 
			
		||||
		components = append(components, cdx.Component{
 | 
			
		||||
			BOMRef:     purl,
 | 
			
		||||
			Type:       cdx.ComponentTypeLibrary,
 | 
			
		||||
			Name:       pack.Name,
 | 
			
		||||
			Version:    pack.Version,
 | 
			
		||||
			PackageURL: purl,
 | 
			
		||||
			Properties: &props,
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		ospkgToPURL[pack.Name] = purl
 | 
			
		||||
	}
 | 
			
		||||
	return components
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cpeToCdxComponents(scannedCves models.VulnInfos) []cdx.Component {
 | 
			
		||||
	cpes := map[string]struct{}{}
 | 
			
		||||
	for _, cve := range scannedCves {
 | 
			
		||||
		for _, cpe := range cve.CpeURIs {
 | 
			
		||||
			cpes[cpe] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(cpes) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	components := []cdx.Component{
 | 
			
		||||
		{
 | 
			
		||||
			BOMRef: uuid.NewString(),
 | 
			
		||||
			Type:   cdx.ComponentTypeApplication,
 | 
			
		||||
			Name:   "CPEs",
 | 
			
		||||
			Properties: &[]cdx.Property{
 | 
			
		||||
				{
 | 
			
		||||
					Name:  "future-architect:vuls:Type",
 | 
			
		||||
					Value: "CPE",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for cpe := range cpes {
 | 
			
		||||
		components = append(components, cdx.Component{
 | 
			
		||||
			BOMRef: cpe,
 | 
			
		||||
			Type:   cdx.ComponentTypeLibrary,
 | 
			
		||||
			Name:   cpe,
 | 
			
		||||
			CPE:    cpe,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return components
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func libpkgToCdxComponents(libscanner models.LibraryScanner, libpkgToPURL map[string]map[string]string) []cdx.Component {
 | 
			
		||||
	components := []cdx.Component{
 | 
			
		||||
		{
 | 
			
		||||
			BOMRef: uuid.NewString(),
 | 
			
		||||
			Type:   cdx.ComponentTypeApplication,
 | 
			
		||||
			Name:   libscanner.LockfilePath,
 | 
			
		||||
			Properties: &[]cdx.Property{
 | 
			
		||||
				{
 | 
			
		||||
					Name:  "future-architect:vuls:Type",
 | 
			
		||||
					Value: libscanner.Type,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, lib := range libscanner.Libs {
 | 
			
		||||
		purl := packageurl.NewPackageURL(libscanner.Type, "", lib.Name, lib.Version, packageurl.Qualifiers{{Key: "file_path", Value: libscanner.LockfilePath}}, "").ToString()
 | 
			
		||||
		components = append(components, cdx.Component{
 | 
			
		||||
			BOMRef:     purl,
 | 
			
		||||
			Type:       cdx.ComponentTypeLibrary,
 | 
			
		||||
			Name:       lib.Name,
 | 
			
		||||
			Version:    lib.Version,
 | 
			
		||||
			PackageURL: purl,
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		libpkgToPURL[libscanner.LockfilePath][lib.Name] = purl
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return components
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wppkgToCdxComponents(wppkgs models.WordPressPackages, wppkgToPURL map[string]string) []cdx.Component {
 | 
			
		||||
	if len(wppkgs) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	components := []cdx.Component{
 | 
			
		||||
		{
 | 
			
		||||
			BOMRef: uuid.NewString(),
 | 
			
		||||
			Type:   cdx.ComponentTypeApplication,
 | 
			
		||||
			Name:   "wordpress",
 | 
			
		||||
			Properties: &[]cdx.Property{
 | 
			
		||||
				{
 | 
			
		||||
					Name:  "future-architect:vuls:Type",
 | 
			
		||||
					Value: "WordPress",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, wppkg := range wppkgs {
 | 
			
		||||
		purl := packageurl.NewPackageURL("wordpress", wppkg.Type, wppkg.Name, wppkg.Version, packageurl.Qualifiers{{Key: "status", Value: wppkg.Status}}, "").ToString()
 | 
			
		||||
		components = append(components, cdx.Component{
 | 
			
		||||
			BOMRef:     purl,
 | 
			
		||||
			Type:       cdx.ComponentTypeLibrary,
 | 
			
		||||
			Name:       wppkg.Name,
 | 
			
		||||
			Version:    wppkg.Version,
 | 
			
		||||
			PackageURL: purl,
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		wppkgToPURL[wppkg.Name] = purl
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return components
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxDependencies(bomRefs map[string][]string) *[]cdx.Dependency {
 | 
			
		||||
	dependencies := make([]cdx.Dependency, 0, len(bomRefs))
 | 
			
		||||
	for ref, depRefs := range bomRefs {
 | 
			
		||||
		ds := depRefs
 | 
			
		||||
		dependencies = append(dependencies, cdx.Dependency{
 | 
			
		||||
			Ref:          ref,
 | 
			
		||||
			Dependencies: &ds,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return &dependencies
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toPkgPURL(osFamily, osVersion, packName, packVersion, packRelease, packArch, packRepository string) string {
 | 
			
		||||
	var purlType string
 | 
			
		||||
	switch osFamily {
 | 
			
		||||
	case constant.Alma, constant.Amazon, constant.CentOS, constant.Fedora, constant.OpenSUSE, constant.OpenSUSELeap, constant.Oracle, constant.RedHat, constant.Rocky, constant.SUSEEnterpriseDesktop, constant.SUSEEnterpriseServer:
 | 
			
		||||
		purlType = "rpm"
 | 
			
		||||
	case constant.Alpine:
 | 
			
		||||
		purlType = "apk"
 | 
			
		||||
	case constant.Debian, constant.Raspbian, constant.Ubuntu:
 | 
			
		||||
		purlType = "deb"
 | 
			
		||||
	case constant.FreeBSD:
 | 
			
		||||
		purlType = "pkg"
 | 
			
		||||
	case constant.Windows:
 | 
			
		||||
		purlType = "win"
 | 
			
		||||
	case constant.ServerTypePseudo:
 | 
			
		||||
		purlType = "pseudo"
 | 
			
		||||
	default:
 | 
			
		||||
		purlType = "unknown"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	version := packVersion
 | 
			
		||||
	if packRelease != "" {
 | 
			
		||||
		version = fmt.Sprintf("%s-%s", packVersion, packRelease)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var qualifiers packageurl.Qualifiers
 | 
			
		||||
	if osVersion != "" {
 | 
			
		||||
		qualifiers = append(qualifiers, packageurl.Qualifier{
 | 
			
		||||
			Key:   "distro",
 | 
			
		||||
			Value: osVersion,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if packArch != "" {
 | 
			
		||||
		qualifiers = append(qualifiers, packageurl.Qualifier{
 | 
			
		||||
			Key:   "arch",
 | 
			
		||||
			Value: packArch,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if packRepository != "" {
 | 
			
		||||
		qualifiers = append(qualifiers, packageurl.Qualifier{
 | 
			
		||||
			Key:   "repo",
 | 
			
		||||
			Value: packRepository,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return packageurl.NewPackageURL(purlType, osFamily, packName, version, qualifiers, "").ToString()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxVulnerabilities(result models.ScanResult, ospkgToPURL map[string]string, libpkgToPURL map[string]map[string]string, wppkgToPURL map[string]string) *[]cdx.Vulnerability {
 | 
			
		||||
	vulnerabilities := make([]cdx.Vulnerability, 0, len(result.ScannedCves))
 | 
			
		||||
	for _, cve := range result.ScannedCves {
 | 
			
		||||
		vulnerabilities = append(vulnerabilities, cdx.Vulnerability{
 | 
			
		||||
			ID:          cve.CveID,
 | 
			
		||||
			Ratings:     cdxRatings(cve.CveContents),
 | 
			
		||||
			CWEs:        cdxCWEs(cve.CveContents),
 | 
			
		||||
			Description: cdxDescription(cve.CveContents),
 | 
			
		||||
			Advisories:  cdxAdvisories(cve.CveContents),
 | 
			
		||||
			Affects:     cdxAffects(cve, ospkgToPURL, libpkgToPURL, wppkgToPURL),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return &vulnerabilities
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxRatings(cveContents models.CveContents) *[]cdx.VulnerabilityRating {
 | 
			
		||||
	var ratings []cdx.VulnerabilityRating
 | 
			
		||||
	for _, contents := range cveContents {
 | 
			
		||||
		for _, content := range contents {
 | 
			
		||||
			if content.Cvss2Score != 0 || content.Cvss2Vector != "" || content.Cvss2Severity != "" {
 | 
			
		||||
				ratings = append(ratings, cdxCVSS2Rating(string(content.Type), content.Cvss2Vector, content.Cvss2Score, content.Cvss2Severity))
 | 
			
		||||
			}
 | 
			
		||||
			if content.Cvss3Score != 0 || content.Cvss3Vector != "" || content.Cvss3Severity != "" {
 | 
			
		||||
				ratings = append(ratings, cdxCVSS3Rating(string(content.Type), content.Cvss3Vector, content.Cvss3Score, content.Cvss3Severity))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &ratings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxCVSS2Rating(source, vector string, score float64, severity string) cdx.VulnerabilityRating {
 | 
			
		||||
	r := cdx.VulnerabilityRating{
 | 
			
		||||
		Source: &cdx.Source{Name: source},
 | 
			
		||||
		Method: cdx.ScoringMethodCVSSv2,
 | 
			
		||||
		Vector: vector,
 | 
			
		||||
	}
 | 
			
		||||
	if score != 0 {
 | 
			
		||||
		r.Score = &score
 | 
			
		||||
	}
 | 
			
		||||
	switch strings.ToLower(severity) {
 | 
			
		||||
	case "high":
 | 
			
		||||
		r.Severity = cdx.SeverityHigh
 | 
			
		||||
	case "medium":
 | 
			
		||||
		r.Severity = cdx.SeverityMedium
 | 
			
		||||
	case "low":
 | 
			
		||||
		r.Severity = cdx.SeverityLow
 | 
			
		||||
	default:
 | 
			
		||||
		r.Severity = cdx.SeverityUnknown
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxCVSS3Rating(source, vector string, score float64, severity string) cdx.VulnerabilityRating {
 | 
			
		||||
	r := cdx.VulnerabilityRating{
 | 
			
		||||
		Source: &cdx.Source{Name: source},
 | 
			
		||||
		Method: cdx.ScoringMethodCVSSv3,
 | 
			
		||||
		Vector: vector,
 | 
			
		||||
	}
 | 
			
		||||
	if strings.HasPrefix(vector, "CVSS:3.1") {
 | 
			
		||||
		r.Method = cdx.ScoringMethodCVSSv31
 | 
			
		||||
	}
 | 
			
		||||
	if score != 0 {
 | 
			
		||||
		r.Score = &score
 | 
			
		||||
	}
 | 
			
		||||
	switch strings.ToLower(severity) {
 | 
			
		||||
	case "critical":
 | 
			
		||||
		r.Severity = cdx.SeverityCritical
 | 
			
		||||
	case "high":
 | 
			
		||||
		r.Severity = cdx.SeverityHigh
 | 
			
		||||
	case "medium":
 | 
			
		||||
		r.Severity = cdx.SeverityMedium
 | 
			
		||||
	case "low":
 | 
			
		||||
		r.Severity = cdx.SeverityLow
 | 
			
		||||
	case "none":
 | 
			
		||||
		r.Severity = cdx.SeverityNone
 | 
			
		||||
	default:
 | 
			
		||||
		r.Severity = cdx.SeverityUnknown
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxAffects(cve models.VulnInfo, ospkgToPURL map[string]string, libpkgToPURL map[string]map[string]string, wppkgToPURL map[string]string) *[]cdx.Affects {
 | 
			
		||||
	affects := make([]cdx.Affects, 0, len(cve.AffectedPackages)+len(cve.CpeURIs)+len(cve.LibraryFixedIns)+len(cve.WpPackageFixStats))
 | 
			
		||||
 | 
			
		||||
	for _, p := range cve.AffectedPackages {
 | 
			
		||||
		affects = append(affects, cdx.Affects{
 | 
			
		||||
			Ref: ospkgToPURL[p.Name],
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	for _, cpe := range cve.CpeURIs {
 | 
			
		||||
		affects = append(affects, cdx.Affects{
 | 
			
		||||
			Ref: cpe,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	for _, lib := range cve.LibraryFixedIns {
 | 
			
		||||
		affects = append(affects, cdx.Affects{
 | 
			
		||||
			Ref: libpkgToPURL[lib.Path][lib.Name],
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	for _, wppack := range cve.WpPackageFixStats {
 | 
			
		||||
		affects = append(affects, cdx.Affects{
 | 
			
		||||
			Ref: wppkgToPURL[wppack.Name],
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &affects
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxCWEs(cveContents models.CveContents) *[]int {
 | 
			
		||||
	m := map[int]struct{}{}
 | 
			
		||||
	for _, contents := range cveContents {
 | 
			
		||||
		for _, content := range contents {
 | 
			
		||||
			for _, cweID := range content.CweIDs {
 | 
			
		||||
				if !strings.HasPrefix(cweID, "CWE-") {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				i, err := strconv.Atoi(strings.TrimPrefix(cweID, "CWE-"))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				m[i] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	cweIDs := maps.Keys(m)
 | 
			
		||||
	return &cweIDs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxDescription(cveContents models.CveContents) string {
 | 
			
		||||
	if contents, ok := cveContents[models.Nvd]; ok {
 | 
			
		||||
		return contents[0].Summary
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cdxAdvisories(cveContents models.CveContents) *[]cdx.Advisory {
 | 
			
		||||
	urls := map[string]struct{}{}
 | 
			
		||||
	for _, contents := range cveContents {
 | 
			
		||||
		for _, content := range contents {
 | 
			
		||||
			if content.SourceLink != "" {
 | 
			
		||||
				urls[content.SourceLink] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
			for _, r := range content.References {
 | 
			
		||||
				urls[r.Link] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	advisories := make([]cdx.Advisory, 0, len(urls))
 | 
			
		||||
	for u := range urls {
 | 
			
		||||
		advisories = append(advisories, cdx.Advisory{
 | 
			
		||||
			URL: u,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return &advisories
 | 
			
		||||
}
 | 
			
		||||
@@ -35,10 +35,10 @@ type message struct {
 | 
			
		||||
 | 
			
		||||
func (w SlackWriter) Write(rs ...models.ScanResult) (err error) {
 | 
			
		||||
 | 
			
		||||
	channel := w.Cnf.Channel
 | 
			
		||||
	for _, r := range rs {
 | 
			
		||||
		w.lang, w.osFamily = r.Lang, r.Family
 | 
			
		||||
		if channel == "${servername}" {
 | 
			
		||||
		channel := w.Cnf.Channel
 | 
			
		||||
		if w.Cnf.Channel == "${servername}" {
 | 
			
		||||
			channel = fmt.Sprintf("#%s", r.ServerName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -103,6 +103,9 @@ func writeToFile(cnf config.Config, path string) error {
 | 
			
		||||
	if cnf.Default.WordPress != nil && cnf.Default.WordPress.IsZero() {
 | 
			
		||||
		cnf.Default.WordPress = nil
 | 
			
		||||
	}
 | 
			
		||||
	if cnf.Default.PortScan != nil && cnf.Default.PortScan.IsZero() {
 | 
			
		||||
		cnf.Default.PortScan = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := struct {
 | 
			
		||||
		Saas    *config.SaasConf             `toml:"saas"`
 | 
			
		||||
@@ -198,5 +201,11 @@ func cleanForTOMLEncoding(server config.ServerInfo, def config.ServerInfo) confi
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if server.PortScan != nil {
 | 
			
		||||
		if server.PortScan.IsZero() || reflect.DeepEqual(server.PortScan, def.PortScan) {
 | 
			
		||||
			server.PortScan = nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return server
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										126
									
								
								scanner/base.go
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								scanner/base.go
									
									
									
									
									
								
							@@ -15,8 +15,8 @@ import (
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/aquasecurity/fanal/analyzer"
 | 
			
		||||
	dio "github.com/aquasecurity/go-dep-parser/pkg/io"
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
 | 
			
		||||
	debver "github.com/knqyf263/go-deb-version"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
@@ -28,23 +28,25 @@ import (
 | 
			
		||||
	"golang.org/x/xerrors"
 | 
			
		||||
 | 
			
		||||
	// Import library scanner
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/dotnet/nuget"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/golang/binary"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/golang/mod"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/java/jar"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/java/pom"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/npm"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/yarn"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/php/composer"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/python/pip"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/python/pipenv"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/python/poetry"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/ruby/bundler"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/rust/cargo"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/deps"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/nuget"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/golang/binary"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/golang/mod"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/java/jar"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/java/pom"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/npm"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/pnpm"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/yarn"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/php/composer"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/pip"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/pipenv"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/poetry"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/ruby/bundler"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/rust/cargo"
 | 
			
		||||
 | 
			
		||||
	// _ "github.com/aquasecurity/fanal/analyzer/language/ruby/gemspec"
 | 
			
		||||
	// _ "github.com/aquasecurity/fanal/analyzer/language/nodejs/pkg"
 | 
			
		||||
	// _ "github.com/aquasecurity/fanal/analyzer/language/python/packaging"
 | 
			
		||||
	// _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/ruby/gemspec"
 | 
			
		||||
	// _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/pkg"
 | 
			
		||||
	// _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/packaging"
 | 
			
		||||
 | 
			
		||||
	nmap "github.com/Ullaakut/nmap/v2"
 | 
			
		||||
)
 | 
			
		||||
@@ -396,10 +398,24 @@ func (l *base) detectRunningOnAws() (ok bool, instanceID string, err error) {
 | 
			
		||||
		r := l.exec(cmd, noSudo)
 | 
			
		||||
		if r.isSuccess() {
 | 
			
		||||
			id := strings.TrimSpace(r.Stdout)
 | 
			
		||||
			if !l.isAwsInstanceID(id) {
 | 
			
		||||
				return false, "", nil
 | 
			
		||||
			if l.isAwsInstanceID(id) {
 | 
			
		||||
				return true, id, nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cmd = "curl -X PUT --max-time 1 --noproxy 169.254.169.254 -H \"X-aws-ec2-metadata-token-ttl-seconds: 300\" http://169.254.169.254/latest/api/token"
 | 
			
		||||
		r = l.exec(cmd, noSudo)
 | 
			
		||||
		if r.isSuccess() {
 | 
			
		||||
			token := strings.TrimSpace(r.Stdout)
 | 
			
		||||
			cmd = fmt.Sprintf("curl -H \"X-aws-ec2-metadata-token: %s\" --max-time 1 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id", token)
 | 
			
		||||
			r = l.exec(cmd, noSudo)
 | 
			
		||||
			if r.isSuccess() {
 | 
			
		||||
				id := strings.TrimSpace(r.Stdout)
 | 
			
		||||
				if !l.isAwsInstanceID(id) {
 | 
			
		||||
					return false, "", nil
 | 
			
		||||
				}
 | 
			
		||||
				return true, id, nil
 | 
			
		||||
			}
 | 
			
		||||
			return true, id, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch r.ExitStatus {
 | 
			
		||||
@@ -587,17 +603,22 @@ func (l *base) scanLibraries() (err error) {
 | 
			
		||||
	libFilemap := map[string]LibFile{}
 | 
			
		||||
	detectFiles := l.ServerInfo.Lockfiles
 | 
			
		||||
 | 
			
		||||
	priv := noSudo
 | 
			
		||||
	if l.getServerInfo().Mode.IsFastRoot() || l.getServerInfo().Mode.IsDeep() {
 | 
			
		||||
		priv = sudo
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// auto detect lockfile
 | 
			
		||||
	if l.ServerInfo.FindLock {
 | 
			
		||||
		findopt := ""
 | 
			
		||||
		for filename := range models.LibraryMap {
 | 
			
		||||
		for _, filename := range models.FindLockFiles {
 | 
			
		||||
			findopt += fmt.Sprintf("-name %q -o ", filename)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// delete last "-o "
 | 
			
		||||
		// find / -type f -and \( -name "package-lock.json" -o -name "yarn.lock" ... \) 2>&1 | grep -v "find: "
 | 
			
		||||
		cmd := fmt.Sprintf(`find / -type f -and \( ` + findopt[:len(findopt)-3] + ` \) 2>&1 | grep -v "find: "`)
 | 
			
		||||
		r := exec(l.ServerInfo, cmd, noSudo)
 | 
			
		||||
		r := exec(l.ServerInfo, cmd, priv)
 | 
			
		||||
		if r.ExitStatus != 0 && r.ExitStatus != 1 {
 | 
			
		||||
			return xerrors.Errorf("Failed to find lock files")
 | 
			
		||||
		}
 | 
			
		||||
@@ -632,7 +653,7 @@ func (l *base) scanLibraries() (err error) {
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			cmd := fmt.Sprintf(`stat -c "%%a" %s`, path)
 | 
			
		||||
			r := exec(l.ServerInfo, cmd, noSudo)
 | 
			
		||||
			r := exec(l.ServerInfo, cmd, priv)
 | 
			
		||||
			if !r.isSuccess() {
 | 
			
		||||
				return xerrors.Errorf("Failed to get target file permission: %s, filepath: %s", r, path)
 | 
			
		||||
			}
 | 
			
		||||
@@ -644,7 +665,7 @@ func (l *base) scanLibraries() (err error) {
 | 
			
		||||
			f.Filemode = os.FileMode(perm)
 | 
			
		||||
 | 
			
		||||
			cmd = fmt.Sprintf("cat %s", path)
 | 
			
		||||
			r = exec(l.ServerInfo, cmd, noSudo)
 | 
			
		||||
			r = exec(l.ServerInfo, cmd, priv)
 | 
			
		||||
			if !r.isSuccess() {
 | 
			
		||||
				return xerrors.Errorf("Failed to get target file contents: %s, filepath: %s", r, path)
 | 
			
		||||
			}
 | 
			
		||||
@@ -663,31 +684,74 @@ func (l *base) scanLibraries() (err error) {
 | 
			
		||||
 | 
			
		||||
// AnalyzeLibraries : detects libs defined in lockfile
 | 
			
		||||
func AnalyzeLibraries(ctx context.Context, libFilemap map[string]LibFile, isOffline bool) (libraryScanners []models.LibraryScanner, err error) {
 | 
			
		||||
	// https://github.com/aquasecurity/trivy/blob/84677903a6fa1b707a32d0e8b2bffc23dde52afa/pkg/fanal/analyzer/const.go
 | 
			
		||||
	disabledAnalyzers := []analyzer.Type{
 | 
			
		||||
		// ======
 | 
			
		||||
		//   OS
 | 
			
		||||
		// ======
 | 
			
		||||
		analyzer.TypeOSRelease,
 | 
			
		||||
		analyzer.TypeAlpine,
 | 
			
		||||
		analyzer.TypeAlma,
 | 
			
		||||
		analyzer.TypeAmazon,
 | 
			
		||||
		analyzer.TypeCBLMariner,
 | 
			
		||||
		analyzer.TypeDebian,
 | 
			
		||||
		analyzer.TypePhoton,
 | 
			
		||||
		analyzer.TypeCentOS,
 | 
			
		||||
		analyzer.TypeRocky,
 | 
			
		||||
		analyzer.TypeAlma,
 | 
			
		||||
		analyzer.TypeFedora,
 | 
			
		||||
		analyzer.TypeOracle,
 | 
			
		||||
		analyzer.TypeRedHatBase,
 | 
			
		||||
		analyzer.TypeRocky,
 | 
			
		||||
		analyzer.TypeSUSE,
 | 
			
		||||
		analyzer.TypeUbuntu,
 | 
			
		||||
 | 
			
		||||
		// OS Package
 | 
			
		||||
		analyzer.TypeApk,
 | 
			
		||||
		analyzer.TypeDpkg,
 | 
			
		||||
		analyzer.TypeDpkgLicense,
 | 
			
		||||
		analyzer.TypeRpm,
 | 
			
		||||
		analyzer.TypeRpmqa,
 | 
			
		||||
 | 
			
		||||
		// OS Package Repository
 | 
			
		||||
		analyzer.TypeApkRepo,
 | 
			
		||||
 | 
			
		||||
		// ============
 | 
			
		||||
		// Image Config
 | 
			
		||||
		// ============
 | 
			
		||||
		analyzer.TypeApkCommand,
 | 
			
		||||
 | 
			
		||||
		// =================
 | 
			
		||||
		// Structured Config
 | 
			
		||||
		// =================
 | 
			
		||||
		analyzer.TypeYaml,
 | 
			
		||||
		analyzer.TypeTOML,
 | 
			
		||||
		analyzer.TypeJSON,
 | 
			
		||||
		analyzer.TypeDockerfile,
 | 
			
		||||
		analyzer.TypeHCL,
 | 
			
		||||
		analyzer.TypeTerraform,
 | 
			
		||||
		analyzer.TypeCloudFormation,
 | 
			
		||||
		analyzer.TypeHelm,
 | 
			
		||||
 | 
			
		||||
		// ========
 | 
			
		||||
		// License
 | 
			
		||||
		// ========
 | 
			
		||||
		analyzer.TypeLicenseFile,
 | 
			
		||||
 | 
			
		||||
		// ========
 | 
			
		||||
		// Secrets
 | 
			
		||||
		// ========
 | 
			
		||||
		analyzer.TypeSecret,
 | 
			
		||||
 | 
			
		||||
		// =======
 | 
			
		||||
		// Red Hat
 | 
			
		||||
		// =======
 | 
			
		||||
		analyzer.TypeRedHatContentManifestType,
 | 
			
		||||
		analyzer.TypeRedHatDockerfileType,
 | 
			
		||||
	}
 | 
			
		||||
	anal, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{
 | 
			
		||||
		Group:             analyzer.GroupBuiltin,
 | 
			
		||||
		DisabledAnalyzers: disabledAnalyzers,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, xerrors.Errorf("Failed to new analyzer group. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	anal := analyzer.NewAnalyzerGroup(analyzer.GroupBuiltin, disabledAnalyzers)
 | 
			
		||||
 | 
			
		||||
	for path, f := range libFilemap {
 | 
			
		||||
		var wg sync.WaitGroup
 | 
			
		||||
@@ -732,13 +796,13 @@ func (d *DummyFileInfo) Size() int64 { return d.size }
 | 
			
		||||
// Mode is
 | 
			
		||||
func (d *DummyFileInfo) Mode() os.FileMode { return d.filemode }
 | 
			
		||||
 | 
			
		||||
//ModTime is
 | 
			
		||||
// ModTime is
 | 
			
		||||
func (d *DummyFileInfo) ModTime() time.Time { return time.Now() }
 | 
			
		||||
 | 
			
		||||
// IsDir is
 | 
			
		||||
func (d *DummyFileInfo) IsDir() bool { return false }
 | 
			
		||||
 | 
			
		||||
//Sys is
 | 
			
		||||
// Sys is
 | 
			
		||||
func (d *DummyFileInfo) Sys() interface{} { return nil }
 | 
			
		||||
 | 
			
		||||
func (l *base) scanWordPress() error {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,18 +4,21 @@ import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/dotnet/nuget"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/golang/binary"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/golang/mod"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/java/jar"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/npm"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/yarn"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/php/composer"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/python/pip"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/python/pipenv"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/python/poetry"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/ruby/bundler"
 | 
			
		||||
	_ "github.com/aquasecurity/fanal/analyzer/language/rust/cargo"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/deps"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/nuget"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/golang/binary"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/golang/mod"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/java/jar"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/java/pom"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/npm"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/pnpm"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/yarn"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/php/composer"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/pip"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/pipenv"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/poetry"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/ruby/bundler"
 | 
			
		||||
	_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/rust/cargo"
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package scanner
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/aquasecurity/fanal/types"
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/fanal/types"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -200,68 +200,64 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
 | 
			
		||||
		// Fedora release 35 (Thirty Five)
 | 
			
		||||
		if r := exec(c, "cat /etc/redhat-release", noSudo); r.isSuccess() {
 | 
			
		||||
			result := releasePattern.FindStringSubmatch(strings.TrimSpace(r.Stdout))
 | 
			
		||||
			if len(result) != 3 {
 | 
			
		||||
				rhel := newRHEL(c)
 | 
			
		||||
				rhel.setErrs([]error{xerrors.Errorf("Failed to parse /etc/redhat-release. r.Stdout: %s", r.Stdout)})
 | 
			
		||||
				return true, rhel
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			release := result[2]
 | 
			
		||||
			major, err := strconv.Atoi(util.Major(release))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				rhel := newRHEL(c)
 | 
			
		||||
				rhel.setErrs([]error{xerrors.Errorf("Failed to parse major version from release: %s", release)})
 | 
			
		||||
				return true, rhel
 | 
			
		||||
			}
 | 
			
		||||
			switch strings.ToLower(result[1]) {
 | 
			
		||||
			case "fedora":
 | 
			
		||||
				fed := newFedora(c)
 | 
			
		||||
				if major < 32 {
 | 
			
		||||
					fed.setErrs([]error{xerrors.Errorf("Failed to init Fedora. err: not supported major version. versions prior to Fedora 32 are not supported, detected version is %s", release)})
 | 
			
		||||
					return true, fed
 | 
			
		||||
				}
 | 
			
		||||
				fed.setDistro(constant.Fedora, release)
 | 
			
		||||
				return true, fed
 | 
			
		||||
			case "centos", "centos linux":
 | 
			
		||||
				cent := newCentOS(c)
 | 
			
		||||
				if major < 5 {
 | 
			
		||||
					cent.setErrs([]error{xerrors.Errorf("Failed to init CentOS. err: not supported major version. versions prior to CentOS 5 are not supported, detected version is %s", release)})
 | 
			
		||||
					return true, cent
 | 
			
		||||
				}
 | 
			
		||||
				cent.setDistro(constant.CentOS, release)
 | 
			
		||||
				return true, cent
 | 
			
		||||
			case "centos stream":
 | 
			
		||||
				cent := newCentOS(c)
 | 
			
		||||
				if major < 8 {
 | 
			
		||||
					cent.setErrs([]error{xerrors.Errorf("Failed to init CentOS Stream. err: not supported major version. versions prior to CentOS Stream 8 are not supported, detected version is %s", release)})
 | 
			
		||||
					return true, cent
 | 
			
		||||
				}
 | 
			
		||||
				cent.setDistro(constant.CentOS, fmt.Sprintf("stream%s", release))
 | 
			
		||||
				return true, cent
 | 
			
		||||
			case "alma", "almalinux":
 | 
			
		||||
				alma := newAlma(c)
 | 
			
		||||
				if major < 8 {
 | 
			
		||||
					alma.setErrs([]error{xerrors.Errorf("Failed to init AlmaLinux. err: not supported major version. versions prior to AlmaLinux 8 are not supported, detected version is %s", release)})
 | 
			
		||||
					return true, alma
 | 
			
		||||
				}
 | 
			
		||||
				alma.setDistro(constant.Alma, release)
 | 
			
		||||
				return true, alma
 | 
			
		||||
			case "rocky", "rocky linux":
 | 
			
		||||
				rocky := newRocky(c)
 | 
			
		||||
				if major < 8 {
 | 
			
		||||
					rocky.setErrs([]error{xerrors.Errorf("Failed to init Rocky Linux. err: not supported major version. versions prior to Rocky Linux 8 are not supported, detected version is %s", release)})
 | 
			
		||||
					return true, rocky
 | 
			
		||||
				}
 | 
			
		||||
				rocky.setDistro(constant.Rocky, release)
 | 
			
		||||
				return true, rocky
 | 
			
		||||
			default:
 | 
			
		||||
				rhel := newRHEL(c)
 | 
			
		||||
				if major < 5 {
 | 
			
		||||
					rhel.setErrs([]error{xerrors.Errorf("Failed to init RedHat Enterprise Linux. err: not supported major version. versions prior to RedHat Enterprise Linux 5 are not supported, detected version is %s", release)})
 | 
			
		||||
			if len(result) == 3 {
 | 
			
		||||
				release := result[2]
 | 
			
		||||
				major, err := strconv.Atoi(util.Major(release))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					rhel := newRHEL(c)
 | 
			
		||||
					rhel.setErrs([]error{xerrors.Errorf("Failed to parse major version from release: %s", release)})
 | 
			
		||||
					return true, rhel
 | 
			
		||||
				}
 | 
			
		||||
				switch strings.ToLower(result[1]) {
 | 
			
		||||
				case "fedora":
 | 
			
		||||
					fed := newFedora(c)
 | 
			
		||||
					if major < 32 {
 | 
			
		||||
						fed.setErrs([]error{xerrors.Errorf("Failed to init Fedora. err: not supported major version. versions prior to Fedora 32 are not supported, detected version is %s", release)})
 | 
			
		||||
						return true, fed
 | 
			
		||||
					}
 | 
			
		||||
					fed.setDistro(constant.Fedora, release)
 | 
			
		||||
					return true, fed
 | 
			
		||||
				case "centos", "centos linux":
 | 
			
		||||
					cent := newCentOS(c)
 | 
			
		||||
					if major < 5 {
 | 
			
		||||
						cent.setErrs([]error{xerrors.Errorf("Failed to init CentOS. err: not supported major version. versions prior to CentOS 5 are not supported, detected version is %s", release)})
 | 
			
		||||
						return true, cent
 | 
			
		||||
					}
 | 
			
		||||
					cent.setDistro(constant.CentOS, release)
 | 
			
		||||
					return true, cent
 | 
			
		||||
				case "centos stream":
 | 
			
		||||
					cent := newCentOS(c)
 | 
			
		||||
					if major < 8 {
 | 
			
		||||
						cent.setErrs([]error{xerrors.Errorf("Failed to init CentOS Stream. err: not supported major version. versions prior to CentOS Stream 8 are not supported, detected version is %s", release)})
 | 
			
		||||
						return true, cent
 | 
			
		||||
					}
 | 
			
		||||
					cent.setDistro(constant.CentOS, fmt.Sprintf("stream%s", release))
 | 
			
		||||
					return true, cent
 | 
			
		||||
				case "alma", "almalinux":
 | 
			
		||||
					alma := newAlma(c)
 | 
			
		||||
					if major < 8 {
 | 
			
		||||
						alma.setErrs([]error{xerrors.Errorf("Failed to init AlmaLinux. err: not supported major version. versions prior to AlmaLinux 8 are not supported, detected version is %s", release)})
 | 
			
		||||
						return true, alma
 | 
			
		||||
					}
 | 
			
		||||
					alma.setDistro(constant.Alma, release)
 | 
			
		||||
					return true, alma
 | 
			
		||||
				case "rocky", "rocky linux":
 | 
			
		||||
					rocky := newRocky(c)
 | 
			
		||||
					if major < 8 {
 | 
			
		||||
						rocky.setErrs([]error{xerrors.Errorf("Failed to init Rocky Linux. err: not supported major version. versions prior to Rocky Linux 8 are not supported, detected version is %s", release)})
 | 
			
		||||
						return true, rocky
 | 
			
		||||
					}
 | 
			
		||||
					rocky.setDistro(constant.Rocky, release)
 | 
			
		||||
					return true, rocky
 | 
			
		||||
				default:
 | 
			
		||||
					rhel := newRHEL(c)
 | 
			
		||||
					if major < 5 {
 | 
			
		||||
						rhel.setErrs([]error{xerrors.Errorf("Failed to init RedHat Enterprise Linux. err: not supported major version. versions prior to RedHat Enterprise Linux 5 are not supported, detected version is %s", release)})
 | 
			
		||||
						return true, rhel
 | 
			
		||||
					}
 | 
			
		||||
					rhel.setDistro(constant.RedHat, release)
 | 
			
		||||
					return true, rhel
 | 
			
		||||
				}
 | 
			
		||||
				rhel.setDistro(constant.RedHat, release)
 | 
			
		||||
				return true, rhel
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -448,13 +444,28 @@ func (o *redhatBase) scanInstalledPackages() (models.Packages, error) {
 | 
			
		||||
		Version: version,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r := o.exec(o.rpmQa(), noSudo)
 | 
			
		||||
	var r execResult
 | 
			
		||||
	switch o.getDistro().Family {
 | 
			
		||||
	case constant.Amazon:
 | 
			
		||||
		switch strings.Fields(o.getDistro().Release)[0] {
 | 
			
		||||
		case "2":
 | 
			
		||||
			if o.exec("rpm -q yum-utils", noSudo).isSuccess() {
 | 
			
		||||
				r = o.exec("repoquery --all --pkgnarrow=installed --qf='%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH} %{UI_FROM_REPO}'", o.sudo.repoquery())
 | 
			
		||||
			} else {
 | 
			
		||||
				r = o.exec(o.rpmQa(), noSudo)
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			r = o.exec(o.rpmQa(), noSudo)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		r = o.exec(o.rpmQa(), noSudo)
 | 
			
		||||
	}
 | 
			
		||||
	if !r.isSuccess() {
 | 
			
		||||
		return nil, xerrors.Errorf("Scan packages failed: %s", r)
 | 
			
		||||
	}
 | 
			
		||||
	installed, _, err := o.parseInstalledPackages(r.Stdout)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, xerrors.Errorf("Failed to parse installed packages. err: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return installed, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -469,7 +480,29 @@ func (o *redhatBase) parseInstalledPackages(stdout string) (models.Packages, mod
 | 
			
		||||
		if trimmed := strings.TrimSpace(line); trimmed == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		pack, err := o.parseInstalledPackagesLine(line)
 | 
			
		||||
 | 
			
		||||
		var (
 | 
			
		||||
			pack *models.Package
 | 
			
		||||
			err  error
 | 
			
		||||
		)
 | 
			
		||||
		switch o.getDistro().Family {
 | 
			
		||||
		case constant.Amazon:
 | 
			
		||||
			switch strings.Fields(o.getDistro().Release)[0] {
 | 
			
		||||
			case "2":
 | 
			
		||||
				switch len(strings.Fields(line)) {
 | 
			
		||||
				case 5:
 | 
			
		||||
					pack, err = o.parseInstalledPackagesLine(line)
 | 
			
		||||
				case 6:
 | 
			
		||||
					pack, err = o.parseInstalledPackagesLineFromRepoquery(line)
 | 
			
		||||
				default:
 | 
			
		||||
					return nil, nil, xerrors.Errorf("Failed to parse package line: %s", line)
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				pack, err = o.parseInstalledPackagesLine(line)
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			pack, err = o.parseInstalledPackagesLine(line)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
@@ -522,6 +555,34 @@ func (o *redhatBase) parseInstalledPackagesLine(line string) (*models.Package, e
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *redhatBase) parseInstalledPackagesLineFromRepoquery(line string) (*models.Package, error) {
 | 
			
		||||
	fields := strings.Fields(line)
 | 
			
		||||
	if len(fields) != 6 {
 | 
			
		||||
		return nil, xerrors.Errorf("Failed to parse package line: %s", line)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ver := ""
 | 
			
		||||
	epoch := fields[1]
 | 
			
		||||
	if epoch == "0" || epoch == "(none)" {
 | 
			
		||||
		ver = fields[2]
 | 
			
		||||
	} else {
 | 
			
		||||
		ver = fmt.Sprintf("%s:%s", epoch, fields[2])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repo := strings.TrimPrefix(fields[5], "@")
 | 
			
		||||
	if repo == "installed" {
 | 
			
		||||
		repo = "amzn2-core"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &models.Package{
 | 
			
		||||
		Name:       fields[0],
 | 
			
		||||
		Version:    ver,
 | 
			
		||||
		Release:    fields[3],
 | 
			
		||||
		Arch:       fields[4],
 | 
			
		||||
		Repository: repo,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *redhatBase) parseRpmQfLine(line string) (pkg *models.Package, ignored bool, err error) {
 | 
			
		||||
	for _, suffix := range []string{
 | 
			
		||||
		"Permission denied",
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,10 @@ import (
 | 
			
		||||
 | 
			
		||||
func TestParseInstalledPackagesLinesRedhat(t *testing.T) {
 | 
			
		||||
	r := newRHEL(config.ServerInfo{})
 | 
			
		||||
	r.Distro = config.Distro{Family: constant.RedHat}
 | 
			
		||||
 | 
			
		||||
	var packagetests = []struct {
 | 
			
		||||
		in       string
 | 
			
		||||
		distro   config.Distro
 | 
			
		||||
		kernel   models.Kernel
 | 
			
		||||
		packages models.Packages
 | 
			
		||||
	}{
 | 
			
		||||
@@ -30,6 +30,7 @@ Percona-Server-shared-56	1	5.6.19	rel67.0.el6 x84_64
 | 
			
		||||
kernel 0 2.6.32 696.20.1.el6 x86_64
 | 
			
		||||
kernel 0 2.6.32 696.20.3.el6 x86_64
 | 
			
		||||
kernel 0 2.6.32 695.20.3.el6 x86_64`,
 | 
			
		||||
			distro: config.Distro{Family: constant.RedHat},
 | 
			
		||||
			kernel: models.Kernel{},
 | 
			
		||||
			packages: models.Packages{
 | 
			
		||||
				"openssl": models.Package{
 | 
			
		||||
@@ -58,6 +59,7 @@ kernel 0 2.6.32 695.20.3.el6 x86_64
 | 
			
		||||
kernel-devel 0 2.6.32 696.20.1.el6 x86_64
 | 
			
		||||
kernel-devel 0 2.6.32 696.20.3.el6 x86_64
 | 
			
		||||
kernel-devel 0 2.6.32 695.20.3.el6 x86_64`,
 | 
			
		||||
			distro: config.Distro{Family: constant.RedHat},
 | 
			
		||||
			kernel: models.Kernel{Release: "2.6.32-696.20.3.el6.x86_64"},
 | 
			
		||||
			packages: models.Packages{
 | 
			
		||||
				"openssl": models.Package{
 | 
			
		||||
@@ -91,6 +93,7 @@ kernel 0 2.6.32 695.20.3.el6 x86_64
 | 
			
		||||
kernel-devel 0 2.6.32 696.20.1.el6 x86_64
 | 
			
		||||
kernel-devel 0 2.6.32 696.20.3.el6 x86_64
 | 
			
		||||
kernel-devel 0 2.6.32 695.20.3.el6 x86_64`,
 | 
			
		||||
			distro: config.Distro{Family: constant.RedHat},
 | 
			
		||||
			kernel: models.Kernel{Release: "2.6.32-695.20.3.el6.x86_64"},
 | 
			
		||||
			packages: models.Packages{
 | 
			
		||||
				"openssl": models.Package{
 | 
			
		||||
@@ -115,9 +118,65 @@ kernel-devel 0 2.6.32 695.20.3.el6 x86_64`,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: `openssl	0	1.0.1e	30.el6.11 x86_64
 | 
			
		||||
Percona-Server-shared-56	1	5.6.19	rel67.0.el6 x84_64
 | 
			
		||||
kernel 0 2.6.32 696.20.1.el6 x86_64
 | 
			
		||||
kernel 0 2.6.32 696.20.3.el6 x86_64
 | 
			
		||||
kernel 0 2.6.32 695.20.3.el6 x86_64`,
 | 
			
		||||
			distro: config.Distro{Family: constant.Amazon, Release: "2 (Karoo)"},
 | 
			
		||||
			kernel: models.Kernel{},
 | 
			
		||||
			packages: models.Packages{
 | 
			
		||||
				"openssl": models.Package{
 | 
			
		||||
					Name:    "openssl",
 | 
			
		||||
					Version: "1.0.1e",
 | 
			
		||||
					Release: "30.el6.11",
 | 
			
		||||
				},
 | 
			
		||||
				"Percona-Server-shared-56": models.Package{
 | 
			
		||||
					Name:    "Percona-Server-shared-56",
 | 
			
		||||
					Version: "1:5.6.19",
 | 
			
		||||
					Release: "rel67.0.el6",
 | 
			
		||||
				},
 | 
			
		||||
				"kernel": models.Package{
 | 
			
		||||
					Name:    "kernel",
 | 
			
		||||
					Version: "2.6.32",
 | 
			
		||||
					Release: "696.20.3.el6",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: `yum-utils 0 1.1.31 46.amzn2.0.1 noarch @amzn2-core
 | 
			
		||||
zlib 0 1.2.7 19.amzn2.0.1 x86_64 installed
 | 
			
		||||
java-1.8.0-amazon-corretto 1 1.8.0_192.b12 1.amzn2 x86_64 @amzn2extra-corretto8`,
 | 
			
		||||
			distro: config.Distro{Family: constant.Amazon, Release: "2 (Karoo)"},
 | 
			
		||||
			packages: models.Packages{
 | 
			
		||||
				"yum-utils": models.Package{
 | 
			
		||||
					Name:       "yum-utils",
 | 
			
		||||
					Version:    "1.1.31",
 | 
			
		||||
					Release:    "46.amzn2.0.1",
 | 
			
		||||
					Arch:       "noarch",
 | 
			
		||||
					Repository: "amzn2-core",
 | 
			
		||||
				},
 | 
			
		||||
				"zlib": models.Package{
 | 
			
		||||
					Name:       "zlib",
 | 
			
		||||
					Version:    "1.2.7",
 | 
			
		||||
					Release:    "19.amzn2.0.1",
 | 
			
		||||
					Arch:       "x86_64",
 | 
			
		||||
					Repository: "amzn2-core",
 | 
			
		||||
				},
 | 
			
		||||
				"java-1.8.0-amazon-corretto": models.Package{
 | 
			
		||||
					Name:       "java-1.8.0-amazon-corretto",
 | 
			
		||||
					Version:    "1:1.8.0_192.b12",
 | 
			
		||||
					Release:    "1.amzn2",
 | 
			
		||||
					Arch:       "x86_64",
 | 
			
		||||
					Repository: "amzn2extra-corretto8",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range packagetests {
 | 
			
		||||
		r.Distro = tt.distro
 | 
			
		||||
		r.Kernel = tt.kernel
 | 
			
		||||
		packages, _, err := r.parseInstalledPackages(tt.in)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -184,6 +243,72 @@ func TestParseInstalledPackagesLine(t *testing.T) {
 | 
			
		||||
			t.Errorf("release: expected %s, actual %s", tt.pack.Release, p.Release)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseInstalledPackagesLineFromRepoquery(t *testing.T) {
 | 
			
		||||
	r := newRHEL(config.ServerInfo{})
 | 
			
		||||
 | 
			
		||||
	var packagetests = []struct {
 | 
			
		||||
		in   string
 | 
			
		||||
		pack models.Package
 | 
			
		||||
		err  bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "yum-utils 0 1.1.31 46.amzn2.0.1 noarch @amzn2-core",
 | 
			
		||||
			pack: models.Package{
 | 
			
		||||
				Name:       "yum-utils",
 | 
			
		||||
				Version:    "1.1.31",
 | 
			
		||||
				Release:    "46.amzn2.0.1",
 | 
			
		||||
				Arch:       "noarch",
 | 
			
		||||
				Repository: "amzn2-core",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "zlib 0 1.2.7 19.amzn2.0.1 x86_64 installed",
 | 
			
		||||
			pack: models.Package{
 | 
			
		||||
				Name:       "zlib",
 | 
			
		||||
				Version:    "1.2.7",
 | 
			
		||||
				Release:    "19.amzn2.0.1",
 | 
			
		||||
				Arch:       "x86_64",
 | 
			
		||||
				Repository: "amzn2-core",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "java-1.8.0-amazon-corretto 1 1.8.0_192.b12 1.amzn2 x86_64 @amzn2extra-corretto8",
 | 
			
		||||
			pack: models.Package{
 | 
			
		||||
				Name:       "java-1.8.0-amazon-corretto",
 | 
			
		||||
				Version:    "1:1.8.0_192.b12",
 | 
			
		||||
				Release:    "1.amzn2",
 | 
			
		||||
				Arch:       "x86_64",
 | 
			
		||||
				Repository: "amzn2extra-corretto8",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, tt := range packagetests {
 | 
			
		||||
		p, err := r.parseInstalledPackagesLineFromRepoquery(tt.in)
 | 
			
		||||
		if err == nil && tt.err {
 | 
			
		||||
			t.Errorf("Expected err not occurred: %d", i)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil && !tt.err {
 | 
			
		||||
			t.Errorf("UnExpected err not occurred: %d", i)
 | 
			
		||||
		}
 | 
			
		||||
		if p.Name != tt.pack.Name {
 | 
			
		||||
			t.Errorf("name: expected %s, actual %s", tt.pack.Name, p.Name)
 | 
			
		||||
		}
 | 
			
		||||
		if p.Version != tt.pack.Version {
 | 
			
		||||
			t.Errorf("version: expected %s, actual %s", tt.pack.Version, p.Version)
 | 
			
		||||
		}
 | 
			
		||||
		if p.Release != tt.pack.Release {
 | 
			
		||||
			t.Errorf("release: expected %s, actual %s", tt.pack.Release, p.Release)
 | 
			
		||||
		}
 | 
			
		||||
		if p.Arch != tt.pack.Arch {
 | 
			
		||||
			t.Errorf("arch: expected %s, actual %s", tt.pack.Arch, p.Arch)
 | 
			
		||||
		}
 | 
			
		||||
		if p.Repository != tt.pack.Repository {
 | 
			
		||||
			t.Errorf("repository: expected %s, actual %s", tt.pack.Repository, p.Repository)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,26 +10,29 @@ import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/aquasecurity/trivy/pkg/utils"
 | 
			
		||||
	"github.com/google/subcommands"
 | 
			
		||||
	"github.com/k0kubun/pp"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
	"github.com/future-architect/vuls/detector"
 | 
			
		||||
	"github.com/future-architect/vuls/logging"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/future-architect/vuls/reporter"
 | 
			
		||||
	"github.com/google/subcommands"
 | 
			
		||||
	"github.com/k0kubun/pp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ReportCmd is subcommand for reporting
 | 
			
		||||
type ReportCmd struct {
 | 
			
		||||
	configPath string
 | 
			
		||||
 | 
			
		||||
	formatJSON        bool
 | 
			
		||||
	formatOneEMail    bool
 | 
			
		||||
	formatCsv         bool
 | 
			
		||||
	formatFullText    bool
 | 
			
		||||
	formatOneLineText bool
 | 
			
		||||
	formatList        bool
 | 
			
		||||
	gzip              bool
 | 
			
		||||
	formatJSON          bool
 | 
			
		||||
	formatOneEMail      bool
 | 
			
		||||
	formatCsv           bool
 | 
			
		||||
	formatFullText      bool
 | 
			
		||||
	formatOneLineText   bool
 | 
			
		||||
	formatList          bool
 | 
			
		||||
	formatCycloneDXJSON bool
 | 
			
		||||
	formatCycloneDXXML  bool
 | 
			
		||||
	gzip                bool
 | 
			
		||||
 | 
			
		||||
	toSlack      bool
 | 
			
		||||
	toChatWork   bool
 | 
			
		||||
@@ -80,6 +83,9 @@ func (*ReportCmd) Usage() string {
 | 
			
		||||
		[-format-one-line-text]
 | 
			
		||||
		[-format-list]
 | 
			
		||||
		[-format-full-text]
 | 
			
		||||
		[-format-csv]
 | 
			
		||||
		[-format-cyclonedx-json]
 | 
			
		||||
		[-format-cyclonedx-xml]
 | 
			
		||||
		[-gzip]
 | 
			
		||||
		[-http-proxy=http://192.168.0.1:8080]
 | 
			
		||||
		[-debug]
 | 
			
		||||
@@ -150,6 +156,8 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
 | 
			
		||||
	f.BoolVar(&p.formatList, "format-list", false, "Display as list format")
 | 
			
		||||
	f.BoolVar(&p.formatFullText, "format-full-text", false,
 | 
			
		||||
		"Detail report in plain text")
 | 
			
		||||
	f.BoolVar(&p.formatCycloneDXJSON, "format-cyclonedx-json", false, "CycloneDX JSON format")
 | 
			
		||||
	f.BoolVar(&p.formatCycloneDXXML, "format-cyclonedx-xml", false, "CycloneDX XML format")
 | 
			
		||||
 | 
			
		||||
	f.BoolVar(&p.toSlack, "to-slack", false, "Send report via Slack")
 | 
			
		||||
	f.BoolVar(&p.toChatWork, "to-chatwork", false, "Send report via chatwork")
 | 
			
		||||
@@ -225,7 +233,8 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(p.formatJSON || p.formatOneLineText ||
 | 
			
		||||
		p.formatList || p.formatFullText || p.formatCsv) {
 | 
			
		||||
		p.formatList || p.formatFullText || p.formatCsv ||
 | 
			
		||||
		p.formatCycloneDXJSON || p.formatCycloneDXXML) {
 | 
			
		||||
		p.formatList = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -310,15 +319,17 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
 | 
			
		||||
 | 
			
		||||
	if p.toLocalFile {
 | 
			
		||||
		reports = append(reports, reporter.LocalFileWriter{
 | 
			
		||||
			CurrentDir:        dir,
 | 
			
		||||
			DiffPlus:          config.Conf.DiffPlus,
 | 
			
		||||
			DiffMinus:         config.Conf.DiffMinus,
 | 
			
		||||
			FormatJSON:        p.formatJSON,
 | 
			
		||||
			FormatCsv:         p.formatCsv,
 | 
			
		||||
			FormatFullText:    p.formatFullText,
 | 
			
		||||
			FormatOneLineText: p.formatOneLineText,
 | 
			
		||||
			FormatList:        p.formatList,
 | 
			
		||||
			Gzip:              p.gzip,
 | 
			
		||||
			CurrentDir:          dir,
 | 
			
		||||
			DiffPlus:            config.Conf.DiffPlus,
 | 
			
		||||
			DiffMinus:           config.Conf.DiffMinus,
 | 
			
		||||
			FormatJSON:          p.formatJSON,
 | 
			
		||||
			FormatCsv:           p.formatCsv,
 | 
			
		||||
			FormatFullText:      p.formatFullText,
 | 
			
		||||
			FormatOneLineText:   p.formatOneLineText,
 | 
			
		||||
			FormatList:          p.formatList,
 | 
			
		||||
			FormatCycloneDXJSON: p.formatCycloneDXJSON,
 | 
			
		||||
			FormatCycloneDXXML:  p.formatCycloneDXXML,
 | 
			
		||||
			Gzip:                p.gzip,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user