Merge pull request #672 from KeyboardNerd/source_package/feature_type
Implement Feature types
This commit is contained in:
commit
73bc2bc36b
@ -31,11 +31,6 @@ notifications:
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- addons:
|
||||
apt:
|
||||
packages:
|
||||
- rpm
|
||||
postgresql: 9.4
|
||||
- addons:
|
||||
apt:
|
||||
packages:
|
||||
|
@ -232,6 +232,9 @@ type Feature struct {
|
||||
Detector *Detector `protobuf:"bytes,5,opt,name=detector" json:"detector,omitempty"`
|
||||
// The list of vulnerabilities that affect the feature.
|
||||
Vulnerabilities []*Vulnerability `protobuf:"bytes,6,rep,name=vulnerabilities" json:"vulnerabilities,omitempty"`
|
||||
// The feature type indicates if the feature represents a source package or
|
||||
// binary package.
|
||||
FeatureType string `protobuf:"bytes,7,opt,name=feature_type,json=featureType" json:"feature_type,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Feature) Reset() { *m = Feature{} }
|
||||
@ -281,6 +284,13 @@ func (m *Feature) GetVulnerabilities() []*Vulnerability {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Feature) GetFeatureType() string {
|
||||
if m != nil {
|
||||
return m.FeatureType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Layer struct {
|
||||
// The sha256 tarsum for the layer.
|
||||
Hash string `protobuf:"bytes,1,opt,name=hash" json:"hash,omitempty"`
|
||||
@ -1091,89 +1101,90 @@ var _StatusService_serviceDesc = grpc.ServiceDesc{
|
||||
func init() { proto.RegisterFile("api/v3/clairpb/clair.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 1336 bytes of a gzipped FileDescriptorProto
|
||||
// 1350 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x4b, 0x6f, 0x1b, 0x55,
|
||||
0x14, 0x66, 0x9c, 0x3a, 0xb6, 0x8f, 0xed, 0xc4, 0xbd, 0x49, 0x13, 0x67, 0xd2, 0x47, 0x32, 0x50,
|
||||
0x51, 0x0a, 0xb2, 0x85, 0x5b, 0xa4, 0xb6, 0x2c, 0x90, 0x9b, 0x38, 0x21, 0x52, 0x1b, 0xa2, 0x49,
|
||||
0x1a, 0x09, 0x10, 0x32, 0x37, 0x9e, 0xe3, 0x64, 0x94, 0xf1, 0xcc, 0x30, 0x73, 0x9d, 0xd4, 0xaa,
|
||||
0xca, 0x82, 0x1d, 0x3b, 0x04, 0x0b, 0x56, 0xfc, 0x00, 0x36, 0x88, 0xff, 0xc0, 0x9e, 0x05, 0x6c,
|
||||
0x61, 0xc7, 0x82, 0x3f, 0xc0, 0x1e, 0xdd, 0xc7, 0x4c, 0x66, 0x92, 0x49, 0xe2, 0x76, 0xe5, 0x7b,
|
||||
0xde, 0x8f, 0xfb, 0xdd, 0x73, 0xc6, 0xa0, 0x53, 0xdf, 0x6e, 0x1e, 0xdd, 0x6b, 0xf6, 0x1c, 0x6a,
|
||||
0x07, 0xfe, 0x9e, 0xfc, 0x6d, 0xf8, 0x81, 0xc7, 0x3c, 0x52, 0xe9, 0x79, 0x01, 0x7a, 0x61, 0x43,
|
||||
0xf0, 0xf4, 0x5b, 0xfb, 0x9e, 0xb7, 0xef, 0x60, 0x53, 0xc8, 0xf6, 0x86, 0xfd, 0x26, 0xb3, 0x07,
|
||||
0x18, 0x32, 0x3a, 0xf0, 0xa5, 0xba, 0x7e, 0x5d, 0x29, 0x70, 0x8f, 0xd4, 0x75, 0x3d, 0x46, 0x99,
|
||||
0xed, 0xb9, 0xa1, 0x94, 0x1a, 0x3f, 0xe6, 0xa0, 0xba, 0x3b, 0x74, 0x5c, 0x0c, 0xe8, 0x9e, 0xed,
|
||||
0xd8, 0x6c, 0x44, 0x08, 0x5c, 0x71, 0xe9, 0x00, 0xeb, 0xda, 0x92, 0x76, 0xa7, 0x64, 0x8a, 0x33,
|
||||
0xb9, 0x0d, 0x53, 0xfc, 0x37, 0xf4, 0x69, 0x0f, 0xbb, 0x42, 0x9a, 0x13, 0xd2, 0x6a, 0xcc, 0xdd,
|
||||
0xe4, 0x6a, 0x4b, 0x50, 0xb6, 0x30, 0xec, 0x05, 0xb6, 0xcf, 0x43, 0xd4, 0x27, 0x84, 0x4e, 0x92,
|
||||
0xc5, 0x9d, 0x3b, 0xb6, 0x7b, 0x58, 0xbf, 0x22, 0x9d, 0xf3, 0x33, 0xd1, 0xa1, 0x18, 0xe2, 0x11,
|
||||
0x06, 0x36, 0x1b, 0xd5, 0xf3, 0x82, 0x1f, 0xd3, 0x5c, 0x36, 0x40, 0x46, 0x2d, 0xca, 0x68, 0x7d,
|
||||
0x52, 0xca, 0x22, 0x9a, 0x2c, 0x40, 0xb1, 0x6f, 0x3f, 0x47, 0xab, 0xbb, 0x37, 0xaa, 0x17, 0x84,
|
||||
0xac, 0x20, 0xe8, 0xc7, 0x23, 0xf2, 0x18, 0xae, 0xd2, 0x7e, 0x1f, 0x7b, 0x0c, 0xad, 0xee, 0x11,
|
||||
0x06, 0x21, 0x2f, 0xb8, 0x5e, 0x5c, 0x9a, 0xb8, 0x53, 0x6e, 0x5d, 0x6b, 0x24, 0xdb, 0xd7, 0x58,
|
||||
0x43, 0xca, 0x86, 0x01, 0x9a, 0xb5, 0x48, 0x7f, 0x57, 0xa9, 0x1b, 0xbf, 0x6b, 0x50, 0x5c, 0x45,
|
||||
0x86, 0x3d, 0xe6, 0x05, 0x99, 0x4d, 0xa9, 0x43, 0x41, 0xf9, 0x56, 0xdd, 0x88, 0x48, 0xd2, 0x82,
|
||||
0xbc, 0xc5, 0x46, 0x3e, 0x8a, 0x0e, 0x4c, 0xb5, 0xae, 0xa7, 0x43, 0x46, 0x4e, 0x1b, 0xab, 0x3b,
|
||||
0x23, 0x1f, 0x4d, 0xa9, 0x6a, 0x7c, 0x09, 0x79, 0x41, 0x93, 0x45, 0x98, 0x5f, 0xed, 0xec, 0x74,
|
||||
0x56, 0x76, 0x3e, 0x31, 0xbb, 0xab, 0xdd, 0x9d, 0x4f, 0xb7, 0x3a, 0xdd, 0x8d, 0xcd, 0xdd, 0xf6,
|
||||
0x93, 0x8d, 0xd5, 0xda, 0x1b, 0xe4, 0x06, 0x2c, 0x9c, 0x16, 0x6e, 0xb6, 0x9f, 0x76, 0xb6, 0xb7,
|
||||
0xda, 0x2b, 0x9d, 0x9a, 0x96, 0x65, 0xbb, 0xd6, 0x69, 0xef, 0x3c, 0x33, 0x3b, 0xb5, 0x9c, 0xb1,
|
||||
0x0d, 0xa5, 0xcd, 0xe8, 0xba, 0x32, 0x0b, 0x6a, 0x41, 0xd1, 0x52, 0xb9, 0x89, 0x8a, 0xca, 0xad,
|
||||
0xb9, 0xec, 0xcc, 0xcd, 0x58, 0xcf, 0xf8, 0x2e, 0x07, 0x05, 0xd5, 0xc3, 0x4c, 0x9f, 0x1f, 0x40,
|
||||
0x29, 0xc6, 0x88, 0x72, 0x3a, 0x9f, 0x76, 0x1a, 0xe7, 0x64, 0x9e, 0x68, 0x26, 0x7b, 0x3b, 0x91,
|
||||
0xee, 0xed, 0x6d, 0x98, 0x52, 0xc7, 0x6e, 0xdf, 0x0b, 0x06, 0x94, 0x29, 0x2c, 0x55, 0x15, 0x77,
|
||||
0x4d, 0x30, 0x53, 0xb5, 0xe4, 0xc7, 0xab, 0x85, 0x74, 0x60, 0xfa, 0x28, 0xf1, 0x14, 0x6c, 0x0c,
|
||||
0xeb, 0x93, 0x02, 0x33, 0x8b, 0x69, 0xd3, 0xd4, 0x7b, 0x31, 0x4f, 0xdb, 0x18, 0x8b, 0x90, 0x7f,
|
||||
0x42, 0x47, 0x28, 0x40, 0x73, 0x40, 0xc3, 0x83, 0xa8, 0x1f, 0xfc, 0x6c, 0x7c, 0xab, 0x41, 0x79,
|
||||
0x85, 0x7b, 0xd9, 0x66, 0x94, 0x0d, 0x43, 0x72, 0x1f, 0x4a, 0x51, 0xfc, 0xb0, 0xae, 0x89, 0x68,
|
||||
0xe7, 0x25, 0x7a, 0xa2, 0x48, 0x56, 0xa1, 0xe6, 0xd0, 0x90, 0x75, 0x87, 0xbe, 0x45, 0x19, 0x76,
|
||||
0xf9, 0x93, 0x57, 0xcd, 0xd5, 0x1b, 0xf2, 0xb9, 0x37, 0xa2, 0x79, 0xd0, 0xd8, 0x89, 0xe6, 0x81,
|
||||
0x39, 0xc5, 0x6d, 0x9e, 0x09, 0x13, 0xce, 0x34, 0x1e, 0x02, 0x59, 0x47, 0xd6, 0x76, 0x7b, 0x18,
|
||||
0xb2, 0x60, 0x64, 0xe2, 0x57, 0x43, 0x0c, 0x19, 0x79, 0x13, 0xaa, 0x54, 0xb1, 0xba, 0x89, 0xeb,
|
||||
0xac, 0x44, 0x4c, 0x7e, 0x5f, 0xc6, 0xaf, 0x13, 0x30, 0x93, 0xb2, 0x0d, 0x7d, 0xcf, 0x0d, 0x91,
|
||||
0xac, 0x41, 0x31, 0xd2, 0x13, 0x76, 0xe5, 0xd6, 0xdd, 0x74, 0x35, 0x19, 0x46, 0x8d, 0x98, 0x11,
|
||||
0xdb, 0x92, 0xf7, 0x61, 0x32, 0x14, 0x0d, 0x52, 0x65, 0x2d, 0xa4, 0xbd, 0x24, 0x3a, 0x68, 0x2a,
|
||||
0x45, 0xfd, 0x6b, 0xa8, 0x46, 0x8e, 0x64, 0xfb, 0xdf, 0x81, 0xbc, 0xc3, 0x0f, 0x2a, 0x91, 0x99,
|
||||
0xb4, 0x0b, 0xa1, 0x63, 0x4a, 0x0d, 0x3e, 0x2f, 0x64, 0x73, 0xd1, 0xea, 0xf6, 0x25, 0x9a, 0x79,
|
||||
0xe4, 0x8b, 0xe6, 0x45, 0xa4, 0xaf, 0x18, 0xa1, 0xfe, 0x93, 0x06, 0xc5, 0x28, 0x81, 0xcc, 0xa7,
|
||||
0x90, 0xba, 0xea, 0xdc, 0xb8, 0x57, 0xbd, 0x0e, 0x93, 0x22, 0xc7, 0xb0, 0x3e, 0x21, 0x4c, 0x9a,
|
||||
0xe3, 0xf7, 0x53, 0x96, 0xa8, 0xcc, 0x8d, 0xbf, 0x73, 0x30, 0xb3, 0xe5, 0x85, 0xaf, 0x75, 0xdf,
|
||||
0x64, 0x0e, 0x26, 0xd5, 0x6b, 0x93, 0xa3, 0x4e, 0x51, 0x64, 0xe5, 0x54, 0x76, 0xef, 0xa6, 0xb3,
|
||||
0xcb, 0x88, 0x27, 0x78, 0xa9, 0xcc, 0xf4, 0xdf, 0x34, 0x28, 0xc5, 0xdc, 0xac, 0x57, 0xc3, 0x79,
|
||||
0x3e, 0x65, 0x07, 0x2a, 0xb8, 0x38, 0x13, 0x13, 0x0a, 0x07, 0x48, 0xad, 0x93, 0xd8, 0x0f, 0x5e,
|
||||
0x21, 0x76, 0xe3, 0x63, 0x69, 0xda, 0x71, 0xb9, 0x34, 0x72, 0xa4, 0x3f, 0x82, 0x4a, 0x52, 0x40,
|
||||
0x6a, 0x30, 0x71, 0x88, 0x23, 0x95, 0x0a, 0x3f, 0x92, 0x59, 0xc8, 0x1f, 0x51, 0x67, 0x18, 0x2d,
|
||||
0x40, 0x49, 0x3c, 0xca, 0x3d, 0xd0, 0x8c, 0x0d, 0x98, 0x4d, 0x87, 0x54, 0x4f, 0xe2, 0x04, 0xca,
|
||||
0xda, 0x98, 0x50, 0x36, 0x7e, 0xd1, 0x60, 0x6e, 0x1d, 0xd9, 0xa6, 0xc7, 0xec, 0xbe, 0xdd, 0x13,
|
||||
0xfb, 0x3a, 0xba, 0xad, 0xfb, 0x30, 0xe7, 0x39, 0x56, 0x37, 0x39, 0x73, 0x46, 0x5d, 0x9f, 0xee,
|
||||
0x47, 0xd7, 0x36, 0xeb, 0x39, 0x56, 0x6a, 0x3e, 0x6d, 0xd1, 0x7d, 0x0e, 0xbd, 0x39, 0x17, 0x8f,
|
||||
0xb3, 0xac, 0x64, 0x19, 0xb3, 0x2e, 0x1e, 0x9f, 0xb5, 0x9a, 0x85, 0xbc, 0x63, 0x0f, 0x6c, 0x26,
|
||||
0x46, 0x70, 0xde, 0x94, 0x44, 0x0c, 0xed, 0x2b, 0x27, 0xd0, 0x36, 0xfe, 0xca, 0xc1, 0xfc, 0x99,
|
||||
0x84, 0x55, 0xfd, 0xbb, 0x50, 0x71, 0x13, 0x7c, 0xd5, 0x85, 0xd6, 0x19, 0x18, 0x67, 0x19, 0x37,
|
||||
0x52, 0xcc, 0x94, 0x1f, 0xfd, 0x5f, 0x0d, 0x2a, 0x49, 0xf1, 0x79, 0x3b, 0xba, 0x17, 0x20, 0x65,
|
||||
0x68, 0x45, 0x3b, 0x5a, 0x91, 0xfc, 0xcb, 0x42, 0xba, 0x43, 0x4b, 0xad, 0x98, 0x98, 0xe6, 0x56,
|
||||
0x16, 0x3a, 0xc8, 0xad, 0x64, 0x95, 0x11, 0x49, 0x1e, 0xc2, 0x84, 0xe7, 0x58, 0x6a, 0xa3, 0xbc,
|
||||
0x7d, 0x0a, 0x70, 0x74, 0x1f, 0xe3, 0xde, 0x3b, 0xa8, 0x80, 0x60, 0x63, 0x68, 0x72, 0x1b, 0x6e,
|
||||
0xea, 0xe2, 0xb1, 0xf8, 0x8a, 0x79, 0x15, 0x53, 0x17, 0x8f, 0x8d, 0x3f, 0x72, 0xb0, 0x70, 0xae,
|
||||
0x0a, 0x59, 0x86, 0x4a, 0x6f, 0x18, 0x04, 0xe8, 0xb2, 0x24, 0x10, 0xca, 0x8a, 0x27, 0x6e, 0x72,
|
||||
0x11, 0x4a, 0x2e, 0x3e, 0x67, 0xc9, 0x2b, 0x2f, 0x72, 0xc6, 0x05, 0xd7, 0xdc, 0x86, 0x6a, 0x0a,
|
||||
0x2e, 0xa2, 0x13, 0x97, 0xac, 0xc2, 0xb4, 0x05, 0xf9, 0x1c, 0x80, 0xc6, 0x69, 0xd6, 0xf3, 0xe2,
|
||||
0x91, 0x7e, 0x38, 0x66, 0xe1, 0x8d, 0x0d, 0xd7, 0xc2, 0xe7, 0x68, 0xb5, 0x13, 0x53, 0xc8, 0x4c,
|
||||
0xb8, 0xd3, 0x3f, 0x82, 0x99, 0x0c, 0x15, 0x5e, 0x8c, 0xcd, 0xd9, 0xa2, 0x0b, 0x79, 0x53, 0x12,
|
||||
0x31, 0x34, 0x72, 0x09, 0xcc, 0xde, 0x83, 0x1b, 0x4f, 0x69, 0x70, 0x98, 0x84, 0x50, 0x3b, 0x34,
|
||||
0x91, 0x5a, 0xd1, 0x53, 0xcb, 0xc0, 0x93, 0xb1, 0x04, 0x37, 0xcf, 0x33, 0x92, 0x88, 0x35, 0x08,
|
||||
0xd4, 0xd6, 0x91, 0xa9, 0x07, 0x2d, 0x3d, 0x19, 0x6b, 0x70, 0x35, 0xc1, 0x7b, 0xed, 0xb9, 0xd0,
|
||||
0xfa, 0x4f, 0x83, 0xe9, 0xa8, 0xda, 0x6d, 0x0c, 0x8e, 0xec, 0x1e, 0x92, 0x21, 0x94, 0x13, 0x3b,
|
||||
0x80, 0x2c, 0x5d, 0xb0, 0x1e, 0x44, 0x32, 0xfa, 0xf2, 0xa5, 0x0b, 0xc4, 0x58, 0xfe, 0xe6, 0xcf,
|
||||
0x7f, 0x7e, 0xc8, 0x2d, 0x92, 0x85, 0x66, 0xb4, 0x04, 0x9a, 0x2f, 0x52, 0x3b, 0xe2, 0x25, 0x39,
|
||||
0x84, 0x4a, 0x72, 0xda, 0x91, 0xe5, 0x4b, 0x87, 0xaf, 0x6e, 0x5c, 0xa4, 0xa2, 0x22, 0xcf, 0x8a,
|
||||
0xc8, 0x53, 0x46, 0x29, 0x8e, 0xfc, 0x48, 0xbb, 0xdb, 0xfa, 0x39, 0x07, 0x33, 0xc9, 0x96, 0x47,
|
||||
0xb5, 0xbf, 0x84, 0xe9, 0x53, 0x83, 0x83, 0xbc, 0x75, 0xc9, 0x5c, 0x91, 0xa9, 0xdc, 0x1e, 0x6b,
|
||||
0xfa, 0x18, 0x37, 0x44, 0x36, 0xf3, 0xe4, 0x5a, 0x33, 0x39, 0x79, 0xc2, 0xe6, 0x0b, 0xd9, 0x83,
|
||||
0xef, 0x35, 0x98, 0xcb, 0x46, 0x03, 0x39, 0xb5, 0x07, 0x2f, 0x04, 0x9a, 0xfe, 0xde, 0x78, 0xca,
|
||||
0xe9, 0xa4, 0xee, 0x66, 0x27, 0xd5, 0x72, 0xa1, 0x2a, 0x51, 0x13, 0x35, 0xe9, 0x0b, 0x28, 0xc5,
|
||||
0xe0, 0x23, 0x37, 0xcf, 0x14, 0x9e, 0x42, 0xaa, 0x7e, 0xeb, 0x5c, 0xb9, 0x8a, 0x3e, 0x2d, 0xa2,
|
||||
0x97, 0x48, 0xa1, 0x29, 0x31, 0xf9, 0xf8, 0x26, 0xcc, 0xf4, 0xbc, 0x41, 0xda, 0xcc, 0xdf, 0xfb,
|
||||
0xac, 0xa0, 0xfe, 0xb9, 0xee, 0x4d, 0x8a, 0x0f, 0xd1, 0x7b, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff,
|
||||
0xcb, 0x5c, 0xce, 0x34, 0xd2, 0x0e, 0x00, 0x00,
|
||||
0x1a, 0x09, 0x10, 0x1a, 0x6e, 0x3c, 0xc7, 0xc9, 0x28, 0xe3, 0x19, 0x33, 0x73, 0x9d, 0xd4, 0xaa,
|
||||
0xca, 0x82, 0x1d, 0x5b, 0x58, 0xb0, 0xe2, 0x07, 0xb0, 0x41, 0x48, 0xfc, 0x04, 0xf6, 0x2c, 0x60,
|
||||
0x0b, 0x3b, 0x16, 0xfc, 0x01, 0xf6, 0xe8, 0x3e, 0x66, 0x32, 0x93, 0x4c, 0x12, 0xb7, 0x2b, 0xdf,
|
||||
0x7b, 0xde, 0x8f, 0xef, 0x9e, 0x33, 0x06, 0x9d, 0x0e, 0x9c, 0xe6, 0xd1, 0xbd, 0x66, 0xd7, 0xa5,
|
||||
0x4e, 0x30, 0xd8, 0x93, 0xbf, 0x8d, 0x41, 0xe0, 0x33, 0x9f, 0x54, 0xba, 0x7e, 0x80, 0x7e, 0xd8,
|
||||
0x10, 0x34, 0xfd, 0xd6, 0xbe, 0xef, 0xef, 0xbb, 0xd8, 0x14, 0xbc, 0xbd, 0x61, 0xaf, 0xc9, 0x9c,
|
||||
0x3e, 0x86, 0x8c, 0xf6, 0x07, 0x52, 0x5c, 0xbf, 0xae, 0x04, 0xb8, 0x45, 0xea, 0x79, 0x3e, 0xa3,
|
||||
0xcc, 0xf1, 0xbd, 0x50, 0x72, 0x8d, 0x1f, 0x72, 0x50, 0xdd, 0x1d, 0xba, 0x1e, 0x06, 0x74, 0xcf,
|
||||
0x71, 0x1d, 0x36, 0x22, 0x04, 0xae, 0x78, 0xb4, 0x8f, 0x75, 0x6d, 0x49, 0xbb, 0x53, 0x32, 0xc5,
|
||||
0x99, 0xdc, 0x86, 0x29, 0xfe, 0x1b, 0x0e, 0x68, 0x17, 0x2d, 0xc1, 0xcd, 0x09, 0x6e, 0x35, 0xa6,
|
||||
0x6e, 0x72, 0xb1, 0x25, 0x28, 0xdb, 0x18, 0x76, 0x03, 0x67, 0xc0, 0x5d, 0xd4, 0x27, 0x84, 0x4c,
|
||||
0x92, 0xc4, 0x8d, 0xbb, 0x8e, 0x77, 0x58, 0xbf, 0x22, 0x8d, 0xf3, 0x33, 0xd1, 0xa1, 0x18, 0xe2,
|
||||
0x11, 0x06, 0x0e, 0x1b, 0xd5, 0xf3, 0x82, 0x1e, 0xdf, 0x39, 0xaf, 0x8f, 0x8c, 0xda, 0x94, 0xd1,
|
||||
0xfa, 0xa4, 0xe4, 0x45, 0x77, 0xb2, 0x00, 0xc5, 0x9e, 0xf3, 0x1c, 0x6d, 0x6b, 0x6f, 0x54, 0x2f,
|
||||
0x08, 0x5e, 0x41, 0xdc, 0x1f, 0x8f, 0xc8, 0x63, 0xb8, 0x4a, 0x7b, 0x3d, 0xec, 0x32, 0xb4, 0xad,
|
||||
0x23, 0x0c, 0x42, 0x9e, 0x70, 0xbd, 0xb8, 0x34, 0x71, 0xa7, 0xdc, 0xba, 0xd6, 0x48, 0x96, 0xaf,
|
||||
0xb1, 0x86, 0x94, 0x0d, 0x03, 0x34, 0x6b, 0x91, 0xfc, 0xae, 0x12, 0x37, 0x7e, 0xd7, 0xa0, 0xb8,
|
||||
0x8a, 0x0c, 0xbb, 0xcc, 0x0f, 0x32, 0x8b, 0x52, 0x87, 0x82, 0xb2, 0xad, 0xaa, 0x11, 0x5d, 0x49,
|
||||
0x0b, 0xf2, 0x36, 0x1b, 0x0d, 0x50, 0x54, 0x60, 0xaa, 0x75, 0x3d, 0xed, 0x32, 0x32, 0xda, 0x58,
|
||||
0xdd, 0x19, 0x0d, 0xd0, 0x94, 0xa2, 0xc6, 0x97, 0x90, 0x17, 0x77, 0xb2, 0x08, 0xf3, 0xab, 0x9d,
|
||||
0x9d, 0xce, 0xca, 0xce, 0x27, 0xa6, 0xb5, 0x6a, 0xed, 0x7c, 0xba, 0xd5, 0xb1, 0x36, 0x36, 0x77,
|
||||
0xdb, 0x4f, 0x36, 0x56, 0x6b, 0x6f, 0x90, 0x1b, 0xb0, 0x70, 0x9a, 0xb9, 0xd9, 0x7e, 0xda, 0xd9,
|
||||
0xde, 0x6a, 0xaf, 0x74, 0x6a, 0x5a, 0x96, 0xee, 0x5a, 0xa7, 0xbd, 0xf3, 0xcc, 0xec, 0xd4, 0x72,
|
||||
0xc6, 0x36, 0x94, 0x36, 0xa3, 0x76, 0x65, 0x26, 0xd4, 0x82, 0xa2, 0xad, 0x62, 0x13, 0x19, 0x95,
|
||||
0x5b, 0x73, 0xd9, 0x91, 0x9b, 0xb1, 0x9c, 0xf1, 0x6b, 0x0e, 0x0a, 0xaa, 0x86, 0x99, 0x36, 0x3f,
|
||||
0x80, 0x52, 0x8c, 0x11, 0x65, 0x74, 0x3e, 0x6d, 0x34, 0x8e, 0xc9, 0x3c, 0x91, 0x4c, 0xd6, 0x76,
|
||||
0x22, 0x5d, 0xdb, 0xdb, 0x30, 0xa5, 0x8e, 0x56, 0xcf, 0x0f, 0xfa, 0x94, 0x29, 0x2c, 0x55, 0x15,
|
||||
0x75, 0x4d, 0x10, 0x53, 0xb9, 0xe4, 0xc7, 0xcb, 0x85, 0x74, 0x60, 0xfa, 0x28, 0xf1, 0x14, 0x1c,
|
||||
0x0c, 0xeb, 0x93, 0x02, 0x33, 0x8b, 0x69, 0xd5, 0xd4, 0x7b, 0x31, 0x4f, 0xeb, 0x90, 0x65, 0xa8,
|
||||
0xf4, 0x64, 0x45, 0x2c, 0x01, 0x02, 0x89, 0xcd, 0xb2, 0xa2, 0xf1, 0x1e, 0x1b, 0x8b, 0x90, 0x7f,
|
||||
0x42, 0x47, 0x28, 0x70, 0x75, 0x40, 0xc3, 0x83, 0xa8, 0x64, 0xfc, 0x6c, 0x7c, 0xab, 0x41, 0x79,
|
||||
0x85, 0x3b, 0xda, 0x66, 0x94, 0x0d, 0x43, 0x72, 0x1f, 0x4a, 0x51, 0x88, 0x61, 0x5d, 0x13, 0x01,
|
||||
0x9d, 0x97, 0xcb, 0x89, 0x20, 0x59, 0x85, 0x9a, 0x4b, 0x43, 0x66, 0x0d, 0x07, 0x36, 0x65, 0x68,
|
||||
0xf1, 0xa9, 0xa0, 0xea, 0xaf, 0x37, 0xe4, 0x44, 0x68, 0x44, 0x23, 0xa3, 0xb1, 0x13, 0x8d, 0x0c,
|
||||
0x73, 0x8a, 0xeb, 0x3c, 0x13, 0x2a, 0x9c, 0x68, 0x3c, 0x04, 0xb2, 0x8e, 0xac, 0xed, 0x75, 0x31,
|
||||
0x64, 0xc1, 0xc8, 0xc4, 0xaf, 0x86, 0x18, 0x32, 0xf2, 0x26, 0x54, 0xa9, 0x22, 0x59, 0x89, 0x8e,
|
||||
0x57, 0x22, 0x22, 0x6f, 0xa9, 0xf1, 0xcb, 0x04, 0xcc, 0xa4, 0x74, 0xc3, 0x81, 0xef, 0x85, 0x48,
|
||||
0xd6, 0xa0, 0x18, 0xc9, 0x09, 0xbd, 0x72, 0xeb, 0x6e, 0x3a, 0x9b, 0x0c, 0xa5, 0x46, 0x4c, 0x88,
|
||||
0x75, 0xc9, 0xfb, 0x30, 0x19, 0x8a, 0x02, 0xa9, 0xb4, 0x16, 0xd2, 0x56, 0x12, 0x15, 0x34, 0x95,
|
||||
0xa0, 0xfe, 0x35, 0x54, 0x23, 0x43, 0xb2, 0xfc, 0xef, 0x40, 0xde, 0xe5, 0x07, 0x15, 0xc8, 0x4c,
|
||||
0xda, 0x84, 0x90, 0x31, 0xa5, 0x04, 0x1f, 0x29, 0xb2, 0xb8, 0x68, 0x5b, 0xaa, 0x95, 0xdc, 0xf3,
|
||||
0x45, 0x23, 0x25, 0x92, 0x57, 0x84, 0x50, 0xff, 0x51, 0x83, 0x62, 0x14, 0x40, 0xe6, 0x6b, 0x49,
|
||||
0xb5, 0x3a, 0x37, 0x6e, 0xab, 0xd7, 0x61, 0x52, 0xc4, 0x18, 0xd6, 0x27, 0x84, 0x4a, 0x73, 0xfc,
|
||||
0x7a, 0xca, 0x14, 0x95, 0xba, 0xf1, 0x77, 0x0e, 0x66, 0xb6, 0xfc, 0xf0, 0xb5, 0xfa, 0x4d, 0xe6,
|
||||
0x60, 0x52, 0x3d, 0x48, 0x39, 0x0d, 0xd5, 0x8d, 0xac, 0x9c, 0x8a, 0xee, 0xdd, 0x74, 0x74, 0x19,
|
||||
0xfe, 0x04, 0x2d, 0x15, 0x99, 0xfe, 0x9b, 0x06, 0xa5, 0x98, 0x9a, 0xf5, 0x6a, 0x38, 0x6d, 0x40,
|
||||
0xd9, 0x81, 0x72, 0x2e, 0xce, 0xc4, 0x84, 0xc2, 0x01, 0x52, 0xfb, 0xc4, 0xf7, 0x83, 0x57, 0xf0,
|
||||
0xdd, 0xf8, 0x58, 0xaa, 0x76, 0x3c, 0xce, 0x8d, 0x0c, 0xe9, 0x8f, 0xa0, 0x92, 0x64, 0x90, 0x1a,
|
||||
0x4c, 0x1c, 0xe2, 0x48, 0x85, 0xc2, 0x8f, 0x64, 0x16, 0xf2, 0x47, 0xd4, 0x1d, 0x46, 0x3b, 0x52,
|
||||
0x5e, 0x1e, 0xe5, 0x1e, 0x68, 0xc6, 0x06, 0xcc, 0xa6, 0x5d, 0xaa, 0x27, 0x71, 0x02, 0x65, 0x6d,
|
||||
0x4c, 0x28, 0x1b, 0x3f, 0x6b, 0x30, 0xb7, 0x8e, 0x6c, 0xd3, 0x67, 0x4e, 0xcf, 0xe9, 0x8a, 0x95,
|
||||
0x1e, 0x75, 0xeb, 0x3e, 0xcc, 0xf9, 0xae, 0x6d, 0x25, 0xc7, 0xd2, 0xc8, 0x1a, 0xd0, 0xfd, 0xa8,
|
||||
0x6d, 0xb3, 0xbe, 0x6b, 0xa7, 0x46, 0xd8, 0x16, 0xdd, 0xe7, 0xd0, 0x9b, 0xf3, 0xf0, 0x38, 0x4b,
|
||||
0x4b, 0xa6, 0x31, 0xeb, 0xe1, 0xf1, 0x59, 0xad, 0x59, 0xc8, 0xbb, 0x4e, 0xdf, 0x61, 0x62, 0x4a,
|
||||
0xe7, 0x4d, 0x79, 0x89, 0xa1, 0x7d, 0xe5, 0x04, 0xda, 0xc6, 0x5f, 0x39, 0x98, 0x3f, 0x13, 0xb0,
|
||||
0xca, 0x7f, 0x17, 0x2a, 0x5e, 0x82, 0xae, 0xaa, 0xd0, 0x3a, 0x03, 0xe3, 0x2c, 0xe5, 0x46, 0x8a,
|
||||
0x98, 0xb2, 0xa3, 0xff, 0xab, 0x41, 0x25, 0xc9, 0x3e, 0x6f, 0x8d, 0x77, 0x03, 0xa4, 0x0c, 0xed,
|
||||
0x68, 0x8d, 0xab, 0x2b, 0xff, 0xf8, 0x90, 0xe6, 0xd0, 0x56, 0x5b, 0x28, 0xbe, 0x73, 0x2d, 0x1b,
|
||||
0x5d, 0xe4, 0x5a, 0x32, 0xcb, 0xe8, 0x4a, 0x1e, 0xc2, 0x84, 0xef, 0xda, 0x6a, 0xe9, 0xbc, 0x7d,
|
||||
0x0a, 0x70, 0x74, 0x1f, 0xe3, 0xda, 0xbb, 0xa8, 0x80, 0xe0, 0x60, 0x68, 0x72, 0x1d, 0xae, 0xea,
|
||||
0xe1, 0xb1, 0xf8, 0xd0, 0x79, 0x15, 0x55, 0x0f, 0x8f, 0x8d, 0x3f, 0x72, 0xb0, 0x70, 0xae, 0x08,
|
||||
0x5f, 0x49, 0xdd, 0x61, 0x10, 0xa0, 0xc7, 0x92, 0x40, 0x28, 0x2b, 0x9a, 0xe8, 0xe4, 0x22, 0x94,
|
||||
0x3c, 0x7c, 0xce, 0x92, 0x2d, 0x2f, 0x72, 0xc2, 0x05, 0x6d, 0x6e, 0x43, 0x35, 0x05, 0x17, 0x51,
|
||||
0x89, 0x4b, 0xb6, 0x65, 0x5a, 0x83, 0x7c, 0x0e, 0x40, 0xe3, 0x30, 0xeb, 0x79, 0xf1, 0x48, 0x3f,
|
||||
0x1c, 0x33, 0xf1, 0xc6, 0x86, 0x67, 0xe3, 0x73, 0xb4, 0xdb, 0x89, 0x29, 0x64, 0x26, 0xcc, 0xe9,
|
||||
0x1f, 0xc1, 0x4c, 0x86, 0x08, 0x4f, 0xc6, 0xe1, 0x64, 0x51, 0x85, 0xbc, 0x29, 0x2f, 0x31, 0x34,
|
||||
0x72, 0x09, 0xcc, 0xde, 0x83, 0x1b, 0x4f, 0x69, 0x70, 0x98, 0x84, 0x50, 0x3b, 0x34, 0x91, 0xda,
|
||||
0xd1, 0x53, 0xcb, 0xc0, 0x93, 0xb1, 0x04, 0x37, 0xcf, 0x53, 0x92, 0x88, 0x35, 0x08, 0xd4, 0xd6,
|
||||
0x91, 0xa9, 0x07, 0x2d, 0x2d, 0x19, 0x6b, 0x70, 0x35, 0x41, 0x7b, 0xed, 0xb9, 0xd0, 0xfa, 0x4f,
|
||||
0x83, 0xe9, 0x28, 0xdb, 0x6d, 0x0c, 0x8e, 0x9c, 0x2e, 0x92, 0x21, 0x94, 0x13, 0x3b, 0x80, 0x2c,
|
||||
0x5d, 0xb0, 0x1e, 0x44, 0x30, 0xfa, 0xf2, 0xa5, 0x0b, 0xc4, 0x58, 0xfe, 0xe6, 0xcf, 0x7f, 0xbe,
|
||||
0xcf, 0x2d, 0x92, 0x85, 0x66, 0xb4, 0x04, 0x9a, 0x2f, 0x52, 0x3b, 0xe2, 0x25, 0x39, 0x84, 0x4a,
|
||||
0x72, 0xda, 0x91, 0xe5, 0x4b, 0x87, 0xaf, 0x6e, 0x5c, 0x24, 0xa2, 0x3c, 0xcf, 0x0a, 0xcf, 0x53,
|
||||
0x46, 0x29, 0xf6, 0xfc, 0x48, 0xbb, 0xdb, 0xfa, 0x29, 0x07, 0x33, 0xc9, 0x92, 0x47, 0xb9, 0xbf,
|
||||
0x84, 0xe9, 0x53, 0x83, 0x83, 0xbc, 0x75, 0xc9, 0x5c, 0x91, 0xa1, 0xdc, 0x1e, 0x6b, 0xfa, 0x18,
|
||||
0x37, 0x44, 0x34, 0xf3, 0xe4, 0x5a, 0x33, 0x39, 0x79, 0xc2, 0xe6, 0x0b, 0x59, 0x83, 0xef, 0x34,
|
||||
0x98, 0xcb, 0x46, 0x03, 0x39, 0xb5, 0x07, 0x2f, 0x04, 0x9a, 0xfe, 0xde, 0x78, 0xc2, 0xe9, 0xa0,
|
||||
0xee, 0x66, 0x07, 0xd5, 0xf2, 0xa0, 0x2a, 0x51, 0x13, 0x15, 0xe9, 0x0b, 0x28, 0xc5, 0xe0, 0x23,
|
||||
0x37, 0xcf, 0x24, 0x9e, 0x42, 0xaa, 0x7e, 0xeb, 0x5c, 0xbe, 0xf2, 0x3e, 0x2d, 0xbc, 0x97, 0x48,
|
||||
0xa1, 0x29, 0x31, 0xf9, 0xf8, 0x26, 0xcc, 0x74, 0xfd, 0x7e, 0x5a, 0x6d, 0xb0, 0xf7, 0x59, 0x41,
|
||||
0xfd, 0xb9, 0xdd, 0x9b, 0x14, 0x1f, 0xa2, 0xf7, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x9e,
|
||||
0x9e, 0x7b, 0xf5, 0x0e, 0x00, 0x00,
|
||||
}
|
||||
|
@ -80,6 +80,9 @@ message Feature {
|
||||
Detector detector = 5;
|
||||
// The list of vulnerabilities that affect the feature.
|
||||
repeated Vulnerability vulnerabilities = 6;
|
||||
// The feature type indicates if the feature represents a source package or
|
||||
// binary package.
|
||||
string feature_type = 7;
|
||||
}
|
||||
|
||||
message Layer {
|
||||
|
@ -330,6 +330,10 @@
|
||||
"$ref": "#/definitions/clairVulnerability"
|
||||
},
|
||||
"description": "The list of vulnerabilities that affect the feature."
|
||||
},
|
||||
"feature_type": {
|
||||
"type": "string",
|
||||
"description": "The feature type indicates if the feature represents a source package or\nbinary package."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -99,6 +99,7 @@ func NotificationFromDatabaseModel(dbNotification database.VulnerabilityNotifica
|
||||
return ¬i, nil
|
||||
}
|
||||
|
||||
// VulnerabilityFromDatabaseModel converts database Vulnerability to api Vulnerability.
|
||||
func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability) (*Vulnerability, error) {
|
||||
metaString := ""
|
||||
if dbVuln.Metadata != nil {
|
||||
@ -119,6 +120,7 @@ func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability) (*Vulnerabili
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VulnerabilityWithFixedInFromDatabaseModel converts database VulnerabilityWithFixedIn to api Vulnerability.
|
||||
func VulnerabilityWithFixedInFromDatabaseModel(dbVuln database.VulnerabilityWithFixedIn) (*Vulnerability, error) {
|
||||
vuln, err := VulnerabilityFromDatabaseModel(dbVuln.Vulnerability)
|
||||
if err != nil {
|
||||
@ -145,9 +147,11 @@ func NamespacedFeatureFromDatabaseModel(feature database.AncestryFeature) *Featu
|
||||
VersionFormat: feature.Namespace.VersionFormat,
|
||||
Version: version,
|
||||
Detector: DetectorFromDatabaseModel(feature.FeatureBy),
|
||||
FeatureType: string(feature.Type),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectorFromDatabaseModel converts database detector to api detector.
|
||||
func DetectorFromDatabaseModel(detector database.Detector) *Detector {
|
||||
return &Detector{
|
||||
Name: detector.Name,
|
||||
@ -156,6 +160,7 @@ func DetectorFromDatabaseModel(detector database.Detector) *Detector {
|
||||
}
|
||||
}
|
||||
|
||||
// DetectorsFromDatabaseModel converts database detectors to api detectors.
|
||||
func DetectorsFromDatabaseModel(dbDetectors []database.Detector) []*Detector {
|
||||
detectors := make([]*Detector, 0, len(dbDetectors))
|
||||
for _, d := range dbDetectors {
|
||||
|
@ -17,7 +17,6 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@ -27,20 +26,20 @@ import (
|
||||
var (
|
||||
// ErrBackendException is an error that occurs when the database backend
|
||||
// does not work properly (ie. unreachable).
|
||||
ErrBackendException = errors.New("database: an error occurred when querying the backend")
|
||||
ErrBackendException = NewStorageError("an error occurred when querying the backend")
|
||||
|
||||
// ErrInconsistent is an error that occurs when a database consistency check
|
||||
// fails (i.e. when an entity which is supposed to be unique is detected
|
||||
// twice)
|
||||
ErrInconsistent = errors.New("database: inconsistent database")
|
||||
ErrInconsistent = NewStorageError("inconsistent database")
|
||||
|
||||
// ErrInvalidParameters is an error that occurs when the parameters are not valid.
|
||||
ErrInvalidParameters = errors.New("database: parameters are not valid")
|
||||
ErrInvalidParameters = NewStorageError("parameters are not valid")
|
||||
|
||||
// ErrMissingEntities is an error that occurs when an associated immutable
|
||||
// entity doesn't exist in the database. This error can indicate a wrong
|
||||
// implementation or corrupted database.
|
||||
ErrMissingEntities = errors.New("database: associated immutable entities are missing in the database")
|
||||
ErrMissingEntities = NewStorageError("associated immutable entities are missing in the database")
|
||||
)
|
||||
|
||||
// RegistrableComponentConfig is a configuration block that can be used to
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 clair authors
|
||||
// Copyright 2019 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -14,13 +14,22 @@
|
||||
|
||||
package database
|
||||
|
||||
// AffectedFeatureType indicates the type of feature that a vulnerability
|
||||
// affects.
|
||||
type AffectedFeatureType string
|
||||
// StorageError is database error
|
||||
type StorageError struct {
|
||||
reason string
|
||||
original error
|
||||
}
|
||||
|
||||
const (
|
||||
// AffectSourcePackage indicates the vulnerability affects a source package.
|
||||
AffectSourcePackage AffectedFeatureType = "source"
|
||||
// AffectBinaryPackage indicates the vulnerability affects a binary package.
|
||||
AffectBinaryPackage AffectedFeatureType = "binary"
|
||||
)
|
||||
func (e *StorageError) Error() string {
|
||||
return e.reason
|
||||
}
|
||||
|
||||
// NewStorageErrorWithInternalError creates a new database error
|
||||
func NewStorageErrorWithInternalError(reason string, originalError error) *StorageError {
|
||||
return &StorageError{reason, originalError}
|
||||
}
|
||||
|
||||
// NewStorageError creates a new database error
|
||||
func NewStorageError(reason string) *StorageError {
|
||||
return &StorageError{reason, nil}
|
||||
}
|
52
database/feature_type.go
Normal file
52
database/feature_type.go
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2019 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// FeatureType indicates the type of feature that a vulnerability
|
||||
// affects.
|
||||
type FeatureType string
|
||||
|
||||
const (
|
||||
SourcePackage FeatureType = "source"
|
||||
BinaryPackage FeatureType = "binary"
|
||||
)
|
||||
|
||||
var featureTypes = []FeatureType{
|
||||
SourcePackage,
|
||||
BinaryPackage,
|
||||
}
|
||||
|
||||
// Scan implements the database/sql.Scanner interface.
|
||||
func (t *FeatureType) Scan(value interface{}) error {
|
||||
val := value.(string)
|
||||
for _, ft := range featureTypes {
|
||||
if string(ft) == val {
|
||||
*t = ft
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("invalid feature type received from database: '%s'", val))
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver.Valuer interface.
|
||||
func (t *FeatureType) Value() (driver.Value, error) {
|
||||
return string(*t), nil
|
||||
}
|
@ -155,18 +155,33 @@ type Namespace struct {
|
||||
VersionFormat string
|
||||
}
|
||||
|
||||
func NewNamespace(name string, versionFormat string) *Namespace {
|
||||
return &Namespace{name, versionFormat}
|
||||
}
|
||||
|
||||
// Feature represents a package detected in a layer but the namespace is not
|
||||
// determined.
|
||||
//
|
||||
// e.g. Name: Libssl1.0, Version: 1.0, Name: Openssl, Version: 1.0, VersionFormat: dpkg.
|
||||
// e.g. Name: Libssl1.0, Version: 1.0, VersionFormat: dpkg, Type: binary
|
||||
// dpkg is the version format of the installer package manager, which in this
|
||||
// case could be dpkg or apk.
|
||||
type Feature struct {
|
||||
Name string
|
||||
Version string
|
||||
SourceName string
|
||||
SourceVersion string
|
||||
VersionFormat string
|
||||
Type FeatureType
|
||||
}
|
||||
|
||||
func NewFeature(name string, version string, versionFormat string, featureType FeatureType) *Feature {
|
||||
return &Feature{name, version, versionFormat, featureType}
|
||||
}
|
||||
|
||||
func NewBinaryPackage(name string, version string, versionFormat string) *Feature {
|
||||
return &Feature{name, version, versionFormat, BinaryPackage}
|
||||
}
|
||||
|
||||
func NewSourcePackage(name string, version string, versionFormat string) *Feature {
|
||||
return &Feature{name, version, versionFormat, SourcePackage}
|
||||
}
|
||||
|
||||
// NamespacedFeature is a feature with determined namespace and can be affected
|
||||
@ -179,6 +194,11 @@ type NamespacedFeature struct {
|
||||
Namespace Namespace
|
||||
}
|
||||
|
||||
func NewNamespacedFeature(namespace *Namespace, feature *Feature) *NamespacedFeature {
|
||||
// TODO: namespaced feature should use pointer values
|
||||
return &NamespacedFeature{*feature, *namespace}
|
||||
}
|
||||
|
||||
// AffectedNamespacedFeature is a namespaced feature affected by the
|
||||
// vulnerabilities with fixed-in versions for this feature.
|
||||
type AffectedNamespacedFeature struct {
|
||||
@ -199,10 +219,10 @@ type VulnerabilityWithFixedIn struct {
|
||||
// by a Vulnerability. Namespace and Feature Name is unique. Affected Feature is
|
||||
// bound to vulnerability.
|
||||
type AffectedFeature struct {
|
||||
// AffectedType determines which type of package it affects.
|
||||
AffectedType AffectedFeatureType
|
||||
Namespace Namespace
|
||||
FeatureName string
|
||||
// FeatureType determines which type of package it affects.
|
||||
FeatureType FeatureType
|
||||
Namespace Namespace
|
||||
FeatureName string
|
||||
// FixedInVersion is known next feature version that's not affected by the
|
||||
// vulnerability. Empty FixedInVersion means the unaffected version is
|
||||
// unknown.
|
||||
|
@ -23,10 +23,11 @@ const (
|
||||
|
||||
findAncestryFeatures = `
|
||||
SELECT namespace.name, namespace.version_format, feature.name,
|
||||
feature.version, feature.version_format, ancestry_layer.ancestry_index,
|
||||
feature.version, feature.version_format, feature_type.name, ancestry_layer.ancestry_index,
|
||||
ancestry_feature.feature_detector_id, ancestry_feature.namespace_detector_id
|
||||
FROM namespace, feature, namespaced_feature, ancestry_layer, ancestry_feature
|
||||
FROM namespace, feature, feature_type, namespaced_feature, ancestry_layer, ancestry_feature
|
||||
WHERE ancestry_layer.ancestry_id = $1
|
||||
AND feature_type.id = feature.type
|
||||
AND ancestry_feature.ancestry_layer_id = ancestry_layer.id
|
||||
AND ancestry_feature.namespaced_feature_id = namespaced_feature.id
|
||||
AND namespaced_feature.feature_id = feature.id
|
||||
@ -256,6 +257,7 @@ func (tx *pgSession) findAncestryFeatures(ancestryID int64, detectors detectorMa
|
||||
&feature.Feature.Name,
|
||||
&feature.Feature.Version,
|
||||
&feature.Feature.VersionFormat,
|
||||
&feature.Feature.Type,
|
||||
&index,
|
||||
&featureDetectorID,
|
||||
&namespaceDetectorID,
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/ext/versionfmt"
|
||||
@ -65,19 +66,13 @@ func testGenRandomVulnerabilityAndNamespacedFeature(t *testing.T, store database
|
||||
for i := 0; i < numFeatures; i++ {
|
||||
version := rand.Intn(numFeatures)
|
||||
|
||||
features[i] = database.Feature{
|
||||
Name: featureName,
|
||||
VersionFormat: featureVersionFormat,
|
||||
Version: strconv.Itoa(version),
|
||||
}
|
||||
|
||||
features[i] = *database.NewSourcePackage(featureName, strconv.Itoa(version), featureVersionFormat)
|
||||
nsFeatures[i] = database.NamespacedFeature{
|
||||
Namespace: namespace,
|
||||
Feature: features[i],
|
||||
}
|
||||
}
|
||||
|
||||
// insert features
|
||||
if !assert.Nil(t, tx.PersistFeatures(features)) {
|
||||
t.FailNow()
|
||||
}
|
||||
@ -98,6 +93,7 @@ func testGenRandomVulnerabilityAndNamespacedFeature(t *testing.T, store database
|
||||
{
|
||||
Namespace: namespace,
|
||||
FeatureName: featureName,
|
||||
FeatureType: database.SourcePackage,
|
||||
AffectedVersion: strconv.Itoa(version),
|
||||
FixedInVersion: strconv.Itoa(version),
|
||||
},
|
||||
@ -117,7 +113,6 @@ func TestConcurrency(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
defer store.Close()
|
||||
|
||||
start := time.Now()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(100)
|
||||
@ -137,74 +132,33 @@ func TestConcurrency(t *testing.T) {
|
||||
fmt.Println("total", time.Since(start))
|
||||
}
|
||||
|
||||
func genRandomNamespaces(t *testing.T, count int) []database.Namespace {
|
||||
r := make([]database.Namespace, count)
|
||||
for i := 0; i < count; i++ {
|
||||
r[i] = database.Namespace{
|
||||
Name: uuid.New(),
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func TestCaching(t *testing.T) {
|
||||
store, err := openDatabaseForTest("Caching", false)
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
require.Nil(t, err)
|
||||
defer store.Close()
|
||||
|
||||
nsFeatures, vulnerabilities := testGenRandomVulnerabilityAndNamespacedFeature(t, store)
|
||||
|
||||
fmt.Printf("%d features, %d vulnerabilities are generated", len(nsFeatures), len(vulnerabilities))
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tx, err := store.Begin()
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.Nil(t, tx.PersistNamespacedFeatures(nsFeatures))
|
||||
fmt.Println("finished to insert namespaced features")
|
||||
|
||||
tx.Commit()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tx, err := store.Begin()
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.Nil(t, tx.InsertVulnerabilities(vulnerabilities))
|
||||
fmt.Println("finished to insert vulnerabilities")
|
||||
tx.Commit()
|
||||
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
tx, err := store.Begin()
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Nil(t, tx.PersistNamespacedFeatures(nsFeatures))
|
||||
require.Nil(t, tx.Commit())
|
||||
|
||||
tx, err = store.Begin()
|
||||
require.Nil(t, tx.Commit())
|
||||
|
||||
require.Nil(t, tx.InsertVulnerabilities(vulnerabilities))
|
||||
require.Nil(t, tx.Commit())
|
||||
|
||||
tx, err = store.Begin()
|
||||
require.Nil(t, err)
|
||||
defer tx.Rollback()
|
||||
|
||||
// Verify consistency now.
|
||||
affected, err := tx.FindAffectedNamespacedFeatures(nsFeatures)
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
require.Nil(t, err)
|
||||
|
||||
for _, ansf := range affected {
|
||||
if !assert.True(t, ansf.Valid) {
|
||||
t.FailNow()
|
||||
}
|
||||
require.True(t, ansf.Valid)
|
||||
|
||||
expectedAffectedNames := []string{}
|
||||
for _, vuln := range vulnerabilities {
|
||||
@ -220,7 +174,7 @@ func TestCaching(t *testing.T) {
|
||||
actualAffectedNames = append(actualAffectedNames, s.Name)
|
||||
}
|
||||
|
||||
assert.Len(t, strutil.Difference(expectedAffectedNames, actualAffectedNames), 0)
|
||||
assert.Len(t, strutil.Difference(actualAffectedNames, expectedAffectedNames), 0)
|
||||
require.Len(t, strutil.Difference(expectedAffectedNames, actualAffectedNames), 0, "\nvulns: %#v\nfeature:%#v\nexpected:%#v\nactual:%#v", vulnerabilities, ansf.NamespacedFeature, expectedAffectedNames, actualAffectedNames)
|
||||
require.Len(t, strutil.Difference(actualAffectedNames, expectedAffectedNames), 0)
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ const (
|
||||
AND nf.feature_id = f.id
|
||||
AND nf.namespace_id = v.namespace_id
|
||||
AND vaf.feature_name = f.name
|
||||
AND vaf.feature_type = f.type
|
||||
AND vaf.vulnerability_id = v.id
|
||||
AND v.deleted_at IS NULL`
|
||||
|
||||
@ -68,6 +69,11 @@ func (tx *pgSession) PersistFeatures(features []database.Feature) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
types, err := tx.getFeatureTypeMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sorting is needed before inserting into database to prevent deadlock.
|
||||
sort.Slice(features, func(i, j int) bool {
|
||||
return features[i].Name < features[j].Name ||
|
||||
@ -78,13 +84,13 @@ func (tx *pgSession) PersistFeatures(features []database.Feature) error {
|
||||
// TODO(Sida): A better interface for bulk insertion is needed.
|
||||
keys := make([]interface{}, 0, len(features)*3)
|
||||
for _, f := range features {
|
||||
keys = append(keys, f.Name, f.Version, f.VersionFormat)
|
||||
keys = append(keys, f.Name, f.Version, f.VersionFormat, types.byName[f.Type])
|
||||
if f.Name == "" || f.Version == "" || f.VersionFormat == "" {
|
||||
return commonerr.NewBadRequestError("Empty feature name, version or version format is not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
_, err := tx.Exec(queryPersistFeature(len(features)), keys...)
|
||||
_, err = tx.Exec(queryPersistFeature(len(features)), keys...)
|
||||
return handleError("queryPersistFeature", err)
|
||||
}
|
||||
|
||||
@ -240,52 +246,27 @@ func (tx *pgSession) PersistNamespacedFeatures(features []database.NamespacedFea
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindAffectedNamespacedFeatures looks up cache table and retrieves all
|
||||
// vulnerabilities associated with the features.
|
||||
// FindAffectedNamespacedFeatures retrieves vulnerabilities associated with the
|
||||
// feature.
|
||||
func (tx *pgSession) FindAffectedNamespacedFeatures(features []database.NamespacedFeature) ([]database.NullableAffectedNamespacedFeature, error) {
|
||||
if len(features) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
returnFeatures := make([]database.NullableAffectedNamespacedFeature, len(features))
|
||||
|
||||
// featureMap is used to keep track of duplicated features.
|
||||
featureMap := map[database.NamespacedFeature][]*database.NullableAffectedNamespacedFeature{}
|
||||
// initialize return value and generate unique feature request queries.
|
||||
for i, f := range features {
|
||||
returnFeatures[i] = database.NullableAffectedNamespacedFeature{
|
||||
AffectedNamespacedFeature: database.AffectedNamespacedFeature{
|
||||
NamespacedFeature: f,
|
||||
},
|
||||
}
|
||||
|
||||
featureMap[f] = append(featureMap[f], &returnFeatures[i])
|
||||
}
|
||||
|
||||
// query unique namespaced features
|
||||
distinctFeatures := []database.NamespacedFeature{}
|
||||
for f := range featureMap {
|
||||
distinctFeatures = append(distinctFeatures, f)
|
||||
}
|
||||
|
||||
nsFeatureIDs, err := tx.findNamespacedFeatureIDs(distinctFeatures)
|
||||
vulnerableFeatures := make([]database.NullableAffectedNamespacedFeature, len(features))
|
||||
featureIDs, err := tx.findNamespacedFeatureIDs(features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toQuery := []int64{}
|
||||
featureIDMap := map[int64][]*database.NullableAffectedNamespacedFeature{}
|
||||
for i, id := range nsFeatureIDs {
|
||||
for i, id := range featureIDs {
|
||||
if id.Valid {
|
||||
toQuery = append(toQuery, id.Int64)
|
||||
for _, f := range featureMap[distinctFeatures[i]] {
|
||||
f.Valid = id.Valid
|
||||
featureIDMap[id.Int64] = append(featureIDMap[id.Int64], f)
|
||||
}
|
||||
vulnerableFeatures[i].Valid = true
|
||||
vulnerableFeatures[i].NamespacedFeature = features[i]
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := tx.Query(searchNamespacedFeaturesVulnerabilities, pq.Array(toQuery))
|
||||
rows, err := tx.Query(searchNamespacedFeaturesVulnerabilities, pq.Array(featureIDs))
|
||||
if err != nil {
|
||||
return nil, handleError("searchNamespacedFeaturesVulnerabilities", err)
|
||||
}
|
||||
@ -296,6 +277,7 @@ func (tx *pgSession) FindAffectedNamespacedFeatures(features []database.Namespac
|
||||
featureID int64
|
||||
vuln database.VulnerabilityWithFixedIn
|
||||
)
|
||||
|
||||
err := rows.Scan(&featureID,
|
||||
&vuln.Name,
|
||||
&vuln.Description,
|
||||
@ -306,16 +288,19 @@ func (tx *pgSession) FindAffectedNamespacedFeatures(features []database.Namespac
|
||||
&vuln.Namespace.Name,
|
||||
&vuln.Namespace.VersionFormat,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, handleError("searchNamespacedFeaturesVulnerabilities", err)
|
||||
}
|
||||
|
||||
for _, f := range featureIDMap[featureID] {
|
||||
f.AffectedBy = append(f.AffectedBy, vuln)
|
||||
for i, id := range featureIDs {
|
||||
if id.Valid && id.Int64 == featureID {
|
||||
vulnerableFeatures[i].AffectedNamespacedFeature.AffectedBy = append(vulnerableFeatures[i].AffectedNamespacedFeature.AffectedBy, vuln)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnFeatures, nil
|
||||
return vulnerableFeatures, nil
|
||||
}
|
||||
|
||||
func (tx *pgSession) findNamespacedFeatureIDs(nfs []database.NamespacedFeature) ([]sql.NullInt64, error) {
|
||||
@ -323,11 +308,10 @@ func (tx *pgSession) findNamespacedFeatureIDs(nfs []database.NamespacedFeature)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nfsMap := map[database.NamespacedFeature]sql.NullInt64{}
|
||||
keys := make([]interface{}, 0, len(nfs)*4)
|
||||
nfsMap := map[database.NamespacedFeature]int64{}
|
||||
keys := make([]interface{}, 0, len(nfs)*5)
|
||||
for _, nf := range nfs {
|
||||
keys = append(keys, nf.Name, nf.Version, nf.VersionFormat, nf.Namespace.Name)
|
||||
nfsMap[nf] = sql.NullInt64{}
|
||||
keys = append(keys, nf.Name, nf.Version, nf.VersionFormat, nf.Type, nf.Namespace.Name)
|
||||
}
|
||||
|
||||
rows, err := tx.Query(querySearchNamespacedFeature(len(nfs)), keys...)
|
||||
@ -337,12 +321,12 @@ func (tx *pgSession) findNamespacedFeatureIDs(nfs []database.NamespacedFeature)
|
||||
|
||||
defer rows.Close()
|
||||
var (
|
||||
id sql.NullInt64
|
||||
id int64
|
||||
nf database.NamespacedFeature
|
||||
)
|
||||
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&id, &nf.Name, &nf.Version, &nf.VersionFormat, &nf.Namespace.Name)
|
||||
err := rows.Scan(&id, &nf.Name, &nf.Version, &nf.VersionFormat, &nf.Type, &nf.Namespace.Name)
|
||||
nf.Namespace.VersionFormat = nf.VersionFormat
|
||||
if err != nil {
|
||||
return nil, handleError("searchNamespacedFeature", err)
|
||||
@ -352,7 +336,11 @@ func (tx *pgSession) findNamespacedFeatureIDs(nfs []database.NamespacedFeature)
|
||||
|
||||
ids := make([]sql.NullInt64, len(nfs))
|
||||
for i, nf := range nfs {
|
||||
ids[i] = nfsMap[nf]
|
||||
if id, ok := nfsMap[nf]; ok {
|
||||
ids[i] = sql.NullInt64{id, true}
|
||||
} else {
|
||||
ids[i] = sql.NullInt64{}
|
||||
}
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
@ -363,11 +351,17 @@ func (tx *pgSession) findFeatureIDs(fs []database.Feature) ([]sql.NullInt64, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
types, err := tx.getFeatureTypeMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fMap := map[database.Feature]sql.NullInt64{}
|
||||
|
||||
keys := make([]interface{}, 0, len(fs)*3)
|
||||
keys := make([]interface{}, 0, len(fs)*4)
|
||||
for _, f := range fs {
|
||||
keys = append(keys, f.Name, f.Version, f.VersionFormat)
|
||||
typeID := types.byName[f.Type]
|
||||
keys = append(keys, f.Name, f.Version, f.VersionFormat, typeID)
|
||||
fMap[f] = sql.NullInt64{}
|
||||
}
|
||||
|
||||
@ -382,10 +376,13 @@ func (tx *pgSession) findFeatureIDs(fs []database.Feature) ([]sql.NullInt64, err
|
||||
f database.Feature
|
||||
)
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&id, &f.Name, &f.Version, &f.VersionFormat)
|
||||
var typeID int
|
||||
err := rows.Scan(&id, &f.Name, &f.Version, &f.VersionFormat, &typeID)
|
||||
if err != nil {
|
||||
return nil, handleError("querySearchFeatureID", err)
|
||||
}
|
||||
|
||||
f.Type = types.byID[typeID]
|
||||
fMap[f] = id
|
||||
}
|
||||
|
||||
|
@ -18,134 +18,53 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
|
||||
// register dpkg feature lister for testing
|
||||
_ "github.com/coreos/clair/ext/featurefmt/dpkg"
|
||||
)
|
||||
|
||||
func TestPersistFeatures(t *testing.T) {
|
||||
datastore, tx := openSessionForTest(t, "PersistFeatures", false)
|
||||
defer closeTest(t, datastore, tx)
|
||||
tx, cleanup := createTestPgSession(t, "TestPersistFeatures")
|
||||
defer cleanup()
|
||||
|
||||
f1 := database.Feature{}
|
||||
f2 := database.Feature{Name: "n", Version: "v", VersionFormat: "vf"}
|
||||
invalid := database.Feature{}
|
||||
valid := *database.NewBinaryPackage("mount", "2.31.1-0.4ubuntu3.1", "dpkg")
|
||||
|
||||
// empty
|
||||
assert.Nil(t, tx.PersistFeatures([]database.Feature{}))
|
||||
// invalid
|
||||
assert.NotNil(t, tx.PersistFeatures([]database.Feature{f1}))
|
||||
// duplicated
|
||||
assert.Nil(t, tx.PersistFeatures([]database.Feature{f2, f2}))
|
||||
require.NotNil(t, tx.PersistFeatures([]database.Feature{invalid}))
|
||||
// existing
|
||||
assert.Nil(t, tx.PersistFeatures([]database.Feature{f2}))
|
||||
require.Nil(t, tx.PersistFeatures([]database.Feature{valid}))
|
||||
require.Nil(t, tx.PersistFeatures([]database.Feature{valid}))
|
||||
|
||||
fs := listFeatures(t, tx)
|
||||
assert.Len(t, fs, 1)
|
||||
assert.Equal(t, f2, fs[0])
|
||||
features := selectAllFeatures(t, tx)
|
||||
assert.Equal(t, []database.Feature{valid}, features)
|
||||
}
|
||||
|
||||
func TestPersistNamespacedFeatures(t *testing.T) {
|
||||
datastore, tx := openSessionForTest(t, "PersistNamespacedFeatures", true)
|
||||
defer closeTest(t, datastore, tx)
|
||||
tx, cleanup := createTestPgSessionWithFixtures(t, "TestPersistNamespacedFeatures")
|
||||
defer cleanup()
|
||||
|
||||
// existing features
|
||||
f1 := database.Feature{
|
||||
Name: "ourchat",
|
||||
Version: "0.5",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
f1 := database.NewSourcePackage("ourchat", "0.5", "dpkg")
|
||||
// non-existing features
|
||||
f2 := database.Feature{
|
||||
Name: "fake!",
|
||||
}
|
||||
|
||||
f3 := database.Feature{
|
||||
Name: "openssl",
|
||||
Version: "2.0",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
f2 := database.NewSourcePackage("fake!", "", "")
|
||||
// exising namespace
|
||||
n1 := database.Namespace{
|
||||
Name: "debian:7",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
n3 := database.Namespace{
|
||||
Name: "debian:8",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
n1 := database.NewNamespace("debian:7", "dpkg")
|
||||
// non-existing namespace
|
||||
n2 := database.Namespace{
|
||||
Name: "debian:non",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
n2 := database.NewNamespace("debian:non", "dpkg")
|
||||
// existing namespaced feature
|
||||
nf1 := database.NamespacedFeature{
|
||||
Namespace: n1,
|
||||
Feature: f1,
|
||||
}
|
||||
|
||||
nf1 := database.NewNamespacedFeature(n1, f1)
|
||||
// invalid namespaced feature
|
||||
nf2 := database.NamespacedFeature{
|
||||
Namespace: n2,
|
||||
Feature: f2,
|
||||
}
|
||||
|
||||
// new namespaced feature affected by vulnerability
|
||||
nf3 := database.NamespacedFeature{
|
||||
Namespace: n3,
|
||||
Feature: f3,
|
||||
}
|
||||
|
||||
nf2 := database.NewNamespacedFeature(n2, f2)
|
||||
// namespaced features with namespaces or features not in the database will
|
||||
// generate error.
|
||||
assert.Nil(t, tx.PersistNamespacedFeatures([]database.NamespacedFeature{}))
|
||||
|
||||
assert.NotNil(t, tx.PersistNamespacedFeatures([]database.NamespacedFeature{nf1, nf2}))
|
||||
assert.NotNil(t, tx.PersistNamespacedFeatures([]database.NamespacedFeature{*nf1, *nf2}))
|
||||
// valid case: insert nf3
|
||||
assert.Nil(t, tx.PersistNamespacedFeatures([]database.NamespacedFeature{nf1, nf3}))
|
||||
assert.Nil(t, tx.PersistNamespacedFeatures([]database.NamespacedFeature{*nf1}))
|
||||
|
||||
all := listNamespacedFeatures(t, tx)
|
||||
assert.Contains(t, all, nf1)
|
||||
assert.Contains(t, all, nf3)
|
||||
}
|
||||
|
||||
func TestVulnerableFeature(t *testing.T) {
|
||||
datastore, tx := openSessionForTest(t, "VulnerableFeature", true)
|
||||
defer closeTest(t, datastore, tx)
|
||||
|
||||
f1 := database.Feature{
|
||||
Name: "openssl",
|
||||
Version: "1.3",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
n1 := database.Namespace{
|
||||
Name: "debian:7",
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
|
||||
nf1 := database.NamespacedFeature{
|
||||
Namespace: n1,
|
||||
Feature: f1,
|
||||
}
|
||||
assert.Nil(t, tx.PersistFeatures([]database.Feature{f1}))
|
||||
assert.Nil(t, tx.PersistNamespacedFeatures([]database.NamespacedFeature{nf1}))
|
||||
assert.Nil(t, tx.CacheAffectedNamespacedFeatures([]database.NamespacedFeature{nf1}))
|
||||
// ensure the namespaced feature is affected correctly
|
||||
anf, err := tx.FindAffectedNamespacedFeatures([]database.NamespacedFeature{nf1})
|
||||
if assert.Nil(t, err) &&
|
||||
assert.Len(t, anf, 1) &&
|
||||
assert.True(t, anf[0].Valid) &&
|
||||
assert.Len(t, anf[0].AffectedBy, 1) {
|
||||
assert.Equal(t, "CVE-OPENSSL-1-DEB7", anf[0].AffectedBy[0].Name)
|
||||
}
|
||||
assert.Contains(t, all, *nf1)
|
||||
}
|
||||
|
||||
func TestFindAffectedNamespacedFeatures(t *testing.T) {
|
||||
@ -156,6 +75,7 @@ func TestFindAffectedNamespacedFeatures(t *testing.T) {
|
||||
Name: "openssl",
|
||||
Version: "1.0",
|
||||
VersionFormat: "dpkg",
|
||||
Type: database.SourcePackage,
|
||||
},
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian:7",
|
||||
@ -173,30 +93,41 @@ func TestFindAffectedNamespacedFeatures(t *testing.T) {
|
||||
}
|
||||
|
||||
func listNamespacedFeatures(t *testing.T, tx *pgSession) []database.NamespacedFeature {
|
||||
rows, err := tx.Query(`SELECT f.name, f.version, f.version_format, n.name, n.version_format
|
||||
types, err := tx.getFeatureTypeMap()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rows, err := tx.Query(`SELECT f.name, f.version, f.version_format, f.type, n.name, n.version_format
|
||||
FROM feature AS f, namespace AS n, namespaced_feature AS nf
|
||||
WHERE nf.feature_id = f.id AND nf.namespace_id = n.id`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
nf := []database.NamespacedFeature{}
|
||||
for rows.Next() {
|
||||
f := database.NamespacedFeature{}
|
||||
err := rows.Scan(&f.Name, &f.Version, &f.VersionFormat, &f.Namespace.Name, &f.Namespace.VersionFormat)
|
||||
var typeID int
|
||||
err := rows.Scan(&f.Name, &f.Version, &f.VersionFormat, &typeID, &f.Namespace.Name, &f.Namespace.VersionFormat)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f.Type = types.byID[typeID]
|
||||
nf = append(nf, f)
|
||||
}
|
||||
|
||||
return nf
|
||||
}
|
||||
|
||||
func listFeatures(t *testing.T, tx *pgSession) []database.Feature {
|
||||
rows, err := tx.Query("SELECT name, version, version_format FROM feature")
|
||||
func selectAllFeatures(t *testing.T, tx *pgSession) []database.Feature {
|
||||
types, err := tx.getFeatureTypeMap()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rows, err := tx.Query("SELECT name, version, version_format, type FROM feature")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
@ -204,7 +135,9 @@ func listFeatures(t *testing.T, tx *pgSession) []database.Feature {
|
||||
fs := []database.Feature{}
|
||||
for rows.Next() {
|
||||
f := database.Feature{}
|
||||
err := rows.Scan(&f.Name, &f.Version, &f.VersionFormat)
|
||||
var typeID int
|
||||
err := rows.Scan(&f.Name, &f.Version, &f.VersionFormat, &typeID)
|
||||
f.Type = types.byID[typeID]
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
@ -233,3 +166,33 @@ func assertNamespacedFeatureEqual(t *testing.T, expected []database.NamespacedFe
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestFindNamespacedFeatureIDs(t *testing.T) {
|
||||
tx, cleanup := createTestPgSessionWithFixtures(t, "TestFindNamespacedFeatureIDs")
|
||||
defer cleanup()
|
||||
|
||||
features := []database.NamespacedFeature{}
|
||||
expectedIDs := []int{}
|
||||
for id, feature := range realNamespacedFeatures {
|
||||
features = append(features, feature)
|
||||
expectedIDs = append(expectedIDs, id)
|
||||
}
|
||||
|
||||
features = append(features, realNamespacedFeatures[1]) // test duplicated
|
||||
expectedIDs = append(expectedIDs, 1)
|
||||
|
||||
namespace := realNamespaces[1]
|
||||
features = append(features, *database.NewNamespacedFeature(&namespace, database.NewBinaryPackage("not-found", "1.0", "dpkg"))) // test not found feature
|
||||
|
||||
ids, err := tx.findNamespacedFeatureIDs(features)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, ids, len(expectedIDs)+1)
|
||||
for i, id := range ids {
|
||||
if i == len(ids)-1 {
|
||||
require.False(t, id.Valid)
|
||||
} else {
|
||||
require.True(t, id.Valid)
|
||||
require.Equal(t, expectedIDs[i], int(id.Int64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
53
database/pgsql/feature_type.go
Normal file
53
database/pgsql/feature_type.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2019 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pgsql
|
||||
|
||||
import "github.com/coreos/clair/database"
|
||||
|
||||
const (
|
||||
selectAllFeatureTypes = `SELECT id, name FROM feature_type`
|
||||
)
|
||||
|
||||
type featureTypes struct {
|
||||
byID map[int]database.FeatureType
|
||||
byName map[database.FeatureType]int
|
||||
}
|
||||
|
||||
func newFeatureTypes() *featureTypes {
|
||||
return &featureTypes{make(map[int]database.FeatureType), make(map[database.FeatureType]int)}
|
||||
}
|
||||
|
||||
func (tx *pgSession) getFeatureTypeMap() (*featureTypes, error) {
|
||||
rows, err := tx.Query(selectAllFeatureTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
types := newFeatureTypes()
|
||||
for rows.Next() {
|
||||
var (
|
||||
id int
|
||||
name database.FeatureType
|
||||
)
|
||||
if err := rows.Scan(&id, &name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
types.byID[id] = name
|
||||
types.byName[name] = id
|
||||
}
|
||||
|
||||
return types, nil
|
||||
}
|
38
database/pgsql/feature_type_test.go
Normal file
38
database/pgsql/feature_type_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2019 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pgsql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
)
|
||||
|
||||
func TestGetFeatureTypeMap(t *testing.T) {
|
||||
tx, cleanup := createTestPgSession(t, "TestGetFeatureTypeMap")
|
||||
defer cleanup()
|
||||
|
||||
types, err := tx.getFeatureTypeMap()
|
||||
if err != nil {
|
||||
require.Nil(t, err, err.Error())
|
||||
}
|
||||
|
||||
require.Equal(t, database.SourcePackage, types.byID[1])
|
||||
require.Equal(t, database.BinaryPackage, types.byID[2])
|
||||
require.Equal(t, 1, types.byName[database.SourcePackage])
|
||||
require.Equal(t, 2, types.byName[database.BinaryPackage])
|
||||
}
|
@ -37,9 +37,10 @@ const (
|
||||
SELECT id FROM layer WHERE hash = $1`
|
||||
|
||||
findLayerFeatures = `
|
||||
SELECT f.name, f.version, f.version_format, lf.detector_id
|
||||
FROM layer_feature AS lf, feature AS f
|
||||
SELECT f.name, f.version, f.version_format, t.name, lf.detector_id
|
||||
FROM layer_feature AS lf, feature AS f, feature_type AS t
|
||||
WHERE lf.feature_id = f.id
|
||||
AND t.id = f.type
|
||||
AND lf.layer_id = $1`
|
||||
|
||||
findLayerNamespaces = `
|
||||
@ -307,7 +308,7 @@ func (tx *pgSession) findLayerFeatures(layerID int64, detectors detectorMap) ([]
|
||||
detectorID int64
|
||||
feature database.LayerFeature
|
||||
)
|
||||
if err := rows.Scan(&feature.Name, &feature.Version, &feature.VersionFormat, &detectorID); err != nil {
|
||||
if err := rows.Scan(&feature.Name, &feature.Version, &feature.VersionFormat, &feature.Type, &detectorID); err != nil {
|
||||
return nil, handleError("findLayerFeatures", err)
|
||||
}
|
||||
|
||||
|
@ -43,12 +43,12 @@ var persistLayerTests = []struct {
|
||||
features: []database.LayerFeature{
|
||||
{realFeatures[1], realDetectors[1]},
|
||||
},
|
||||
err: "database: parameters are not valid",
|
||||
err: "parameters are not valid",
|
||||
},
|
||||
{
|
||||
title: "layer with non-existing feature",
|
||||
name: "random-forest",
|
||||
err: "database: associated immutable entities are missing in the database",
|
||||
err: "associated immutable entities are missing in the database",
|
||||
by: []database.Detector{realDetectors[2]},
|
||||
features: []database.LayerFeature{
|
||||
{fakeFeatures[1], realDetectors[2]},
|
||||
@ -57,7 +57,7 @@ var persistLayerTests = []struct {
|
||||
{
|
||||
title: "layer with non-existing namespace",
|
||||
name: "random-forest2",
|
||||
err: "database: associated immutable entities are missing in the database",
|
||||
err: "associated immutable entities are missing in the database",
|
||||
by: []database.Detector{realDetectors[1]},
|
||||
namespaces: []database.LayerNamespace{
|
||||
{fakeNamespaces[1], realDetectors[1]},
|
||||
@ -66,7 +66,7 @@ var persistLayerTests = []struct {
|
||||
{
|
||||
title: "layer with non-existing detector",
|
||||
name: "random-forest3",
|
||||
err: "database: associated immutable entities are missing in the database",
|
||||
err: "associated immutable entities are missing in the database",
|
||||
by: []database.Detector{fakeDetector[1]},
|
||||
},
|
||||
{
|
||||
|
@ -19,7 +19,12 @@ var (
|
||||
// the ancestry.
|
||||
entities = MigrationQuery{
|
||||
Up: []string{
|
||||
// namespaces
|
||||
`CREATE TABLE IF NOT EXISTS feature_type (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE);`,
|
||||
|
||||
`INSERT INTO feature_type(name) VALUES ('source'), ('binary')`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS namespace (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NULL,
|
||||
@ -27,13 +32,13 @@ var (
|
||||
UNIQUE (name, version_format));`,
|
||||
`CREATE INDEX ON namespace(name);`,
|
||||
|
||||
// features
|
||||
`CREATE TABLE IF NOT EXISTS feature (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
version TEXT NOT NULL,
|
||||
version_format TEXT NOT NULL,
|
||||
UNIQUE (name, version, version_format));`,
|
||||
type INT REFERENCES feature_type ON DELETE CASCADE,
|
||||
UNIQUE (name, version, version_format, type));`,
|
||||
`CREATE INDEX ON feature(name);`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS namespaced_feature (
|
||||
@ -43,17 +48,15 @@ var (
|
||||
UNIQUE (namespace_id, feature_id));`,
|
||||
},
|
||||
Down: []string{
|
||||
`DROP TABLE IF EXISTS namespace, feature, namespaced_feature CASCADE;`,
|
||||
`DROP TABLE IF EXISTS namespace, feature, namespaced_feature, feature_type CASCADE;`,
|
||||
},
|
||||
}
|
||||
|
||||
// detector is analysis extensions used by the worker.
|
||||
detector = MigrationQuery{
|
||||
Up: []string{
|
||||
// Detector Type
|
||||
`CREATE TYPE detector_type AS ENUM ('namespace', 'feature');`,
|
||||
|
||||
// Detector
|
||||
`CREATE TABLE IF NOT EXISTS detector (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
@ -70,7 +73,6 @@ var (
|
||||
// layer contains all metadata and scanned features and namespaces.
|
||||
layer = MigrationQuery{
|
||||
Up: []string{
|
||||
// layers
|
||||
`CREATE TABLE IF NOT EXISTS layer(
|
||||
id SERIAL PRIMARY KEY,
|
||||
hash TEXT NOT NULL UNIQUE);`,
|
||||
@ -107,7 +109,6 @@ var (
|
||||
// layers.
|
||||
ancestry = MigrationQuery{
|
||||
Up: []string{
|
||||
// ancestry
|
||||
`CREATE TABLE IF NOT EXISTS ancestry (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE);`,
|
||||
@ -145,7 +146,6 @@ var (
|
||||
Up: []string{
|
||||
`CREATE TYPE severity AS ENUM ('Unknown', 'Negligible', 'Low', 'Medium', 'High', 'Critical', 'Defcon1');`,
|
||||
|
||||
// vulnerability
|
||||
`CREATE TABLE IF NOT EXISTS vulnerability (
|
||||
id SERIAL PRIMARY KEY,
|
||||
namespace_id INT REFERENCES Namespace,
|
||||
@ -159,13 +159,18 @@ var (
|
||||
`CREATE INDEX ON vulnerability(namespace_id, name);`,
|
||||
`CREATE INDEX ON vulnerability(namespace_id);`,
|
||||
|
||||
// vulnerability_affected_feature is a de-normalized table to store
|
||||
// the affected features in a independent place other than the
|
||||
// feature table to reduce table lock issue, and makes it easier for
|
||||
// decoupling updater and the Clair main logic.
|
||||
`CREATE TABLE IF NOT EXISTS vulnerability_affected_feature (
|
||||
id SERIAL PRIMARY KEY,
|
||||
vulnerability_id INT REFERENCES vulnerability ON DELETE CASCADE,
|
||||
feature_name TEXT NOT NULL,
|
||||
feature_type INT NOT NULL REFERENCES feature_type ON DELETE CASCADE,
|
||||
affected_version TEXT,
|
||||
fixedin TEXT);`,
|
||||
`CREATE INDEX ON vulnerability_affected_feature(vulnerability_id, feature_name);`,
|
||||
`CREATE INDEX ON vulnerability_affected_feature(vulnerability_id, feature_name, feature_type);`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS vulnerability_affected_namespaced_feature(
|
||||
id SERIAL PRIMARY KEY,
|
||||
@ -176,8 +181,8 @@ var (
|
||||
`CREATE INDEX ON vulnerability_affected_namespaced_feature(namespaced_feature_id);`,
|
||||
},
|
||||
Down: []string{
|
||||
`DROP TYPE IF EXISTS severity;`,
|
||||
`DROP TABLE IF EXISTS vulnerability, vulnerability_affected_feature, vulnerability_affected_namespaced_feature CASCADE;`,
|
||||
`DROP TYPE IF EXISTS severity;`,
|
||||
},
|
||||
}
|
||||
|
||||
|
60
database/pgsql/migrations_test.go
Normal file
60
database/pgsql/migrations_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2019 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pgsql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/remind101/migrate"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coreos/clair/database/pgsql/migrations"
|
||||
)
|
||||
|
||||
var userTableCount = `SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname='public'`
|
||||
|
||||
func TestMigration(t *testing.T) {
|
||||
db, cleanup := createAndConnectTestDB(t, "TestMigration")
|
||||
defer cleanup()
|
||||
|
||||
err := migrate.NewPostgresMigrator(db).Exec(migrate.Up, migrations.Migrations...)
|
||||
if err != nil {
|
||||
require.Nil(t, err, err.Error())
|
||||
}
|
||||
|
||||
err = migrate.NewPostgresMigrator(db).Exec(migrate.Down, migrations.Migrations...)
|
||||
if err != nil {
|
||||
require.Nil(t, err, err.Error())
|
||||
}
|
||||
|
||||
rows, err := db.Query(userTableCount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var (
|
||||
tables []string
|
||||
table string
|
||||
)
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&table); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tables = append(tables, table)
|
||||
}
|
||||
|
||||
require.True(t, len(tables) == 1 && tables[0] == "schema_migrations", "Only `schema_migrations` should be left")
|
||||
}
|
@ -211,8 +211,8 @@ func TestInsertVulnerabilityNotifications(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindNewNotification(t *testing.T) {
|
||||
datastore, tx := openSessionForTest(t, "FindNewNotification", true)
|
||||
defer closeTest(t, datastore, tx)
|
||||
tx, cleanup := createTestPgSessionWithFixtures(t, "TestFindNewNotification")
|
||||
defer cleanup()
|
||||
|
||||
noti, ok, err := tx.FindNewNotification(time.Now())
|
||||
if assert.Nil(t, err) && assert.True(t, ok) {
|
||||
@ -229,7 +229,7 @@ func TestFindNewNotification(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
// can find the notified after a period of time
|
||||
noti, ok, err = tx.FindNewNotification(time.Now().Add(time.Duration(1000)))
|
||||
noti, ok, err = tx.FindNewNotification(time.Now().Add(time.Duration(10 * time.Second)))
|
||||
if assert.Nil(t, err) && assert.True(t, ok) {
|
||||
assert.Equal(t, "test", noti.Name)
|
||||
assert.NotEqual(t, time.Time{}, noti.Notified)
|
||||
|
@ -109,6 +109,7 @@ func dropTemplateDatabase(url string, name string) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
fURL, fName := genTemplateDatabase("fixture", true)
|
||||
nfURL, nfName := genTemplateDatabase("nonfixture", false)
|
||||
|
@ -52,21 +52,22 @@ func querySearchNotDeletedVulnerabilityID(count int) string {
|
||||
|
||||
func querySearchFeatureID(featureCount int) string {
|
||||
return fmt.Sprintf(`
|
||||
SELECT id, name, version, version_format
|
||||
FROM Feature WHERE (name, version, version_format) IN (%s)`,
|
||||
queryString(3, featureCount),
|
||||
SELECT id, name, version, version_format, type
|
||||
FROM Feature WHERE (name, version, version_format, type) IN (%s)`,
|
||||
queryString(4, featureCount),
|
||||
)
|
||||
}
|
||||
|
||||
func querySearchNamespacedFeature(nsfCount int) string {
|
||||
return fmt.Sprintf(`
|
||||
SELECT nf.id, f.name, f.version, f.version_format, n.name
|
||||
FROM namespaced_feature AS nf, feature AS f, namespace AS n
|
||||
SELECT nf.id, f.name, f.version, f.version_format, t.name, n.name
|
||||
FROM namespaced_feature AS nf, feature AS f, namespace AS n, feature_type AS t
|
||||
WHERE nf.feature_id = f.id
|
||||
AND nf.namespace_id = n.id
|
||||
AND n.version_format = f.version_format
|
||||
AND (f.name, f.version, f.version_format, n.name) IN (%s)`,
|
||||
queryString(4, nsfCount),
|
||||
AND f.type = t.id
|
||||
AND (f.name, f.version, f.version_format, t.name, n.name) IN (%s)`,
|
||||
queryString(5, nsfCount),
|
||||
)
|
||||
}
|
||||
|
||||
@ -110,10 +111,11 @@ func queryInsertNotifications(count int) string {
|
||||
func queryPersistFeature(count int) string {
|
||||
return queryPersist(count,
|
||||
"feature",
|
||||
"feature_name_version_version_format_key",
|
||||
"feature_name_version_version_format_type_key",
|
||||
"name",
|
||||
"version",
|
||||
"version_format")
|
||||
"version_format",
|
||||
"type")
|
||||
}
|
||||
|
||||
func queryPersistLayerFeature(count int) string {
|
||||
|
17
database/pgsql/testdata/data.sql
vendored
17
database/pgsql/testdata/data.sql
vendored
@ -4,11 +4,12 @@ INSERT INTO namespace (id, name, version_format) VALUES
|
||||
(2, 'debian:8', 'dpkg'),
|
||||
(3, 'fake:1.0', 'rpm');
|
||||
|
||||
INSERT INTO feature (id, name, version, version_format) VALUES
|
||||
(1, 'ourchat', '0.5', 'dpkg'),
|
||||
(2, 'openssl', '1.0', 'dpkg'),
|
||||
(3, 'openssl', '2.0', 'dpkg'),
|
||||
(4, 'fake', '2.0', 'rpm');
|
||||
INSERT INTO feature (id, name, version, version_format, type) VALUES
|
||||
(1, 'ourchat', '0.5', 'dpkg', 1),
|
||||
(2, 'openssl', '1.0', 'dpkg', 1),
|
||||
(3, 'openssl', '2.0', 'dpkg', 1),
|
||||
(4, 'fake', '2.0', 'rpm', 1),
|
||||
(5, 'mount', '2.31.1-0.4ubuntu3.1', 'dpkg', 2);
|
||||
|
||||
INSERT INTO namespaced_feature(id, feature_id, namespace_id) VALUES
|
||||
(1, 1, 1), -- ourchat 0.5, debian:7
|
||||
@ -112,9 +113,9 @@ INSERT INTO vulnerability (id, namespace_id, name, description, link, severity)
|
||||
INSERT INTO vulnerability (id, namespace_id, name, description, link, severity, deleted_at) VALUES
|
||||
(3, 1, 'CVE-DELETED', '', '', 'Unknown', '2017-08-08 17:49:31.668483');
|
||||
|
||||
INSERT INTO vulnerability_affected_feature(id, vulnerability_id, feature_name, affected_version, fixedin) VALUES
|
||||
(1, 1, 'openssl', '2.0', '2.0'),
|
||||
(2, 1, 'libssl', '1.9-abc', '1.9-abc');
|
||||
INSERT INTO vulnerability_affected_feature(id, vulnerability_id, feature_name, affected_version, fixedin, feature_type) VALUES
|
||||
(1, 1, 'openssl', '2.0', '2.0', 1),
|
||||
(2, 1, 'libssl', '1.9-abc', '1.9-abc', 1);
|
||||
|
||||
INSERT INTO vulnerability_affected_namespaced_feature(id, vulnerability_id, namespaced_feature_id, added_by) VALUES
|
||||
(1, 1, 2, 1);
|
||||
|
@ -15,21 +15,34 @@
|
||||
package pgsql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/remind101/migrate"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/database/pgsql/migrations"
|
||||
"github.com/coreos/clair/pkg/pagination"
|
||||
)
|
||||
|
||||
// int keys must be the consistent with the database ID.
|
||||
var (
|
||||
realFeatures = map[int]database.Feature{
|
||||
1: {"ourchat", "0.5", "ourchat", "0.5", "dpkg"},
|
||||
2: {"openssl", "1.0", "openssl", "1.0", "dpkg"},
|
||||
3: {"openssl", "2.0", "openssl", "2.0", "dpkg"},
|
||||
4: {"fake", "2.0", "fake", "2.0", "rpm"},
|
||||
1: {"ourchat", "0.5", "dpkg", "source"},
|
||||
2: {"openssl", "1.0", "dpkg", "source"},
|
||||
3: {"openssl", "2.0", "dpkg", "source"},
|
||||
4: {"fake", "2.0", "rpm", "source"},
|
||||
5: {"mount", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
}
|
||||
|
||||
realNamespaces = map[int]database.Namespace{
|
||||
@ -146,6 +159,7 @@ var (
|
||||
Name: "ourchat",
|
||||
Version: "0.6",
|
||||
VersionFormat: "dpkg",
|
||||
Type: "source",
|
||||
},
|
||||
}
|
||||
|
||||
@ -260,3 +274,150 @@ func mustMarshalToken(key pagination.Key, v interface{}) pagination.Token {
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
var userDBCount = `SELECT count(datname) FROM pg_database WHERE datistemplate = FALSE AND datname != 'postgres';`
|
||||
|
||||
func createAndConnectTestDB(t *testing.T, testName string) (*sql.DB, func()) {
|
||||
uri := "postgres@127.0.0.1:5432"
|
||||
connectionTemplate := "postgresql://%s?sslmode=disable"
|
||||
if envURI := os.Getenv("CLAIR_TEST_PGSQL"); envURI != "" {
|
||||
uri = envURI
|
||||
}
|
||||
|
||||
db, err := sql.Open("postgres", fmt.Sprintf(connectionTemplate, uri))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testName = strings.ToLower(testName)
|
||||
dbName := fmt.Sprintf("test_%s_%s", testName, time.Now().UTC().Format("2006_01_02_15_04_05"))
|
||||
t.Logf("creating temporary database name = %s", dbName)
|
||||
_, err = db.Exec("CREATE DATABASE " + dbName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testDB, err := sql.Open("postgres", fmt.Sprintf(connectionTemplate, uri+"/"+dbName))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return testDB, func() {
|
||||
t.Logf("cleaning up temporary database %s", dbName)
|
||||
defer db.Close()
|
||||
if err := testDB.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, err := db.Exec(`DROP DATABASE ` + dbName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// ensure the database is cleaned up
|
||||
var count int
|
||||
if err := db.QueryRow(userDBCount).Scan(&count); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createTestPgSQL(t *testing.T, testName string) (*pgSQL, func()) {
|
||||
connection, cleanup := createAndConnectTestDB(t, testName)
|
||||
err := migrate.NewPostgresMigrator(connection).Exec(migrate.Up, migrations.Migrations...)
|
||||
if err != nil {
|
||||
require.Nil(t, err, err.Error())
|
||||
}
|
||||
|
||||
return &pgSQL{connection, nil, Config{PaginationKey: pagination.Must(pagination.NewKey()).String()}}, cleanup
|
||||
}
|
||||
|
||||
func createTestPgSQLWithFixtures(t *testing.T, testName string) (*pgSQL, func()) {
|
||||
connection, cleanup := createTestPgSQL(t, testName)
|
||||
session, err := connection.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer session.Rollback()
|
||||
|
||||
loadFixtures(session.(*pgSession))
|
||||
if err = session.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return connection, cleanup
|
||||
}
|
||||
|
||||
func createTestPgSession(t *testing.T, testName string) (*pgSession, func()) {
|
||||
connection, cleanup := createTestPgSQL(t, testName)
|
||||
session, err := connection.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return session.(*pgSession), func() {
|
||||
session.Rollback()
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
func createTestPgSessionWithFixtures(t *testing.T, testName string) (*pgSession, func()) {
|
||||
tx, cleanup := createTestPgSession(t, testName)
|
||||
defer func() {
|
||||
// ensure to cleanup when loadFixtures failed
|
||||
if r := recover(); r != nil {
|
||||
cleanup()
|
||||
}
|
||||
}()
|
||||
|
||||
loadFixtures(tx)
|
||||
return tx, cleanup
|
||||
}
|
||||
|
||||
func loadFixtures(tx *pgSession) {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
fixturePath := filepath.Join(filepath.Dir(filename)) + "/testdata/data.sql"
|
||||
d, err := ioutil.ReadFile(fixturePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec(string(d))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func assertVulnerabilityWithAffectedEqual(t *testing.T, expected database.VulnerabilityWithAffected, actual database.VulnerabilityWithAffected) bool {
|
||||
return assert.Equal(t, expected.Vulnerability, actual.Vulnerability) && assertAffectedFeaturesEqual(t, expected.Affected, actual.Affected)
|
||||
}
|
||||
|
||||
func assertAffectedFeaturesEqual(t *testing.T, expected []database.AffectedFeature, actual []database.AffectedFeature) bool {
|
||||
if assert.Len(t, actual, len(expected)) {
|
||||
has := map[database.AffectedFeature]bool{}
|
||||
for _, i := range expected {
|
||||
has[i] = false
|
||||
}
|
||||
for _, i := range actual {
|
||||
if visited, ok := has[i]; !ok {
|
||||
return false
|
||||
} else if visited {
|
||||
return false
|
||||
}
|
||||
has[i] = true
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func genRandomNamespaces(t *testing.T, count int) []database.Namespace {
|
||||
r := make([]database.Namespace, count)
|
||||
for i := 0; i < count; i++ {
|
||||
r[i] = database.Namespace{
|
||||
Name: fmt.Sprint(rand.Int()),
|
||||
VersionFormat: "dpkg",
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
@ -39,15 +39,15 @@ const (
|
||||
`
|
||||
|
||||
insertVulnerabilityAffected = `
|
||||
INSERT INTO vulnerability_affected_feature(vulnerability_id, feature_name, affected_version, fixedin)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
INSERT INTO vulnerability_affected_feature(vulnerability_id, feature_name, affected_version, feature_type, fixedin)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING ID
|
||||
`
|
||||
|
||||
searchVulnerabilityAffected = `
|
||||
SELECT vulnerability_id, feature_name, affected_version, fixedin
|
||||
FROM vulnerability_affected_feature
|
||||
WHERE vulnerability_id = ANY($1)
|
||||
SELECT vulnerability_id, feature_name, affected_version, t.name, fixedin
|
||||
FROM vulnerability_affected_feature AS vaf, feature_type AS t
|
||||
WHERE t.id = vaf.feature_type AND vulnerability_id = ANY($1)
|
||||
`
|
||||
|
||||
searchVulnerabilityByID = `
|
||||
@ -58,7 +58,7 @@ const (
|
||||
|
||||
searchVulnerabilityPotentialAffected = `
|
||||
WITH req AS (
|
||||
SELECT vaf.id AS vaf_id, n.id AS n_id, vaf.feature_name AS name, v.id AS vulnerability_id
|
||||
SELECT vaf.id AS vaf_id, n.id AS n_id, vaf.feature_name AS name, vaf.feature_type AS type, v.id AS vulnerability_id
|
||||
FROM vulnerability_affected_feature AS vaf,
|
||||
vulnerability AS v,
|
||||
namespace AS n
|
||||
@ -69,6 +69,7 @@ const (
|
||||
SELECT req.vulnerability_id, nf.id, f.version, req.vaf_id AS added_by
|
||||
FROM feature AS f, namespaced_feature AS nf, req
|
||||
WHERE f.name = req.name
|
||||
AND f.type = req.type
|
||||
AND nf.namespace_id = req.n_id
|
||||
AND nf.feature_id = f.id`
|
||||
|
||||
@ -180,7 +181,7 @@ func (tx *pgSession) FindVulnerabilities(vulnerabilities []database.Vulnerabilit
|
||||
f database.AffectedFeature
|
||||
)
|
||||
|
||||
err := rows.Scan(&id, &f.FeatureName, &f.AffectedVersion, &f.FixedInVersion)
|
||||
err := rows.Scan(&id, &f.FeatureName, &f.AffectedVersion, &f.FeatureType, &f.FixedInVersion)
|
||||
if err != nil {
|
||||
return nil, handleError("searchVulnerabilityAffected", err)
|
||||
}
|
||||
@ -220,6 +221,11 @@ func (tx *pgSession) insertVulnerabilityAffected(vulnerabilityIDs []int64, vulne
|
||||
affectedID int64
|
||||
)
|
||||
|
||||
types, err := tx.getFeatureTypeMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//TODO(Sida): Change to bulk insert.
|
||||
stmt, err := tx.Prepare(insertVulnerabilityAffected)
|
||||
if err != nil {
|
||||
@ -231,7 +237,7 @@ func (tx *pgSession) insertVulnerabilityAffected(vulnerabilityIDs []int64, vulne
|
||||
// affected feature row ID -> affected feature
|
||||
affectedFeatures := map[int64]database.AffectedFeature{}
|
||||
for _, f := range vuln.Affected {
|
||||
err := stmt.QueryRow(vulnerabilityIDs[i], f.FeatureName, f.AffectedVersion, f.FixedInVersion).Scan(&affectedID)
|
||||
err := stmt.QueryRow(vulnerabilityIDs[i], f.FeatureName, f.AffectedVersion, types.byName[f.FeatureType], f.FixedInVersion).Scan(&affectedID)
|
||||
if err != nil {
|
||||
return nil, handleError("insertVulnerabilityAffected", err)
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ func TestCachingVulnerable(t *testing.T) {
|
||||
Name: "openssl",
|
||||
Version: "1.0",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
Type: database.SourcePackage,
|
||||
},
|
||||
Namespace: ns,
|
||||
}
|
||||
@ -120,6 +121,7 @@ func TestCachingVulnerable(t *testing.T) {
|
||||
{
|
||||
Namespace: ns,
|
||||
FeatureName: "openssl",
|
||||
FeatureType: database.SourcePackage,
|
||||
AffectedVersion: "2.0",
|
||||
FixedInVersion: "2.1",
|
||||
},
|
||||
@ -136,6 +138,7 @@ func TestCachingVulnerable(t *testing.T) {
|
||||
{
|
||||
Namespace: ns,
|
||||
FeatureName: "openssl",
|
||||
FeatureType: database.SourcePackage,
|
||||
AffectedVersion: "2.1",
|
||||
FixedInVersion: "2.2",
|
||||
},
|
||||
@ -209,12 +212,14 @@ func TestFindVulnerabilities(t *testing.T) {
|
||||
Affected: []database.AffectedFeature{
|
||||
{
|
||||
FeatureName: "openssl",
|
||||
FeatureType: database.SourcePackage,
|
||||
AffectedVersion: "2.0",
|
||||
FixedInVersion: "2.0",
|
||||
Namespace: ns,
|
||||
},
|
||||
{
|
||||
FeatureName: "libssl",
|
||||
FeatureType: database.SourcePackage,
|
||||
AffectedVersion: "1.9-abc",
|
||||
FixedInVersion: "1.9-abc",
|
||||
Namespace: ns,
|
||||
@ -318,26 +323,3 @@ func TestFindVulnerabilityIDs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertVulnerabilityWithAffectedEqual(t *testing.T, expected database.VulnerabilityWithAffected, actual database.VulnerabilityWithAffected) bool {
|
||||
return assert.Equal(t, expected.Vulnerability, actual.Vulnerability) && assertAffectedFeaturesEqual(t, expected.Affected, actual.Affected)
|
||||
}
|
||||
|
||||
func assertAffectedFeaturesEqual(t *testing.T, expected []database.AffectedFeature, actual []database.AffectedFeature) bool {
|
||||
if assert.Len(t, actual, len(expected)) {
|
||||
has := map[database.AffectedFeature]bool{}
|
||||
for _, i := range expected {
|
||||
has[i] = false
|
||||
}
|
||||
for _, i := range actual {
|
||||
if visited, ok := has[i]; !ok {
|
||||
return false
|
||||
} else if visited {
|
||||
return false
|
||||
}
|
||||
has[i] = true
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
|
||||
line := scanner.Text()
|
||||
if len(line) < 2 {
|
||||
if valid(&pkg) {
|
||||
pkg.Type = database.BinaryPackage
|
||||
packages.Add(pkg)
|
||||
pkg = database.Feature{VersionFormat: dpkg.ParserName}
|
||||
}
|
||||
@ -81,6 +82,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
|
||||
|
||||
// in case of no terminal line
|
||||
if valid(&pkg) {
|
||||
pkg.Type = database.BinaryPackage
|
||||
packages.Add(pkg)
|
||||
}
|
||||
|
||||
|
@ -28,17 +28,17 @@ func TestAPKFeatureDetection(t *testing.T) {
|
||||
"valid case",
|
||||
map[string]string{"lib/apk/db/installed": "apk/testdata/valid"},
|
||||
[]database.Feature{
|
||||
{"musl", "1.1.14-r10", "", "", dpkg.ParserName},
|
||||
{"busybox", "1.24.2-r9", "", "", dpkg.ParserName},
|
||||
{"alpine-baselayout", "3.0.3-r0", "", "", dpkg.ParserName},
|
||||
{"alpine-keys", "1.1-r0", "", "", dpkg.ParserName},
|
||||
{"zlib", "1.2.8-r2", "", "", dpkg.ParserName},
|
||||
{"libcrypto1.0", "1.0.2h-r1", "", "", dpkg.ParserName},
|
||||
{"libssl1.0", "1.0.2h-r1", "", "", dpkg.ParserName},
|
||||
{"apk-tools", "2.6.7-r0", "", "", dpkg.ParserName},
|
||||
{"scanelf", "1.1.6-r0", "", "", dpkg.ParserName},
|
||||
{"musl-utils", "1.1.14-r10", "", "", dpkg.ParserName},
|
||||
{"libc-utils", "0.7-r0", "", "", dpkg.ParserName},
|
||||
{"apk-tools", "2.6.7-r0", "dpkg", "binary"},
|
||||
{"musl", "1.1.14-r10", "dpkg", "binary"},
|
||||
{"libssl1.0", "1.0.2h-r1", "dpkg", "binary"},
|
||||
{"libc-utils", "0.7-r0", "dpkg", "binary"},
|
||||
{"busybox", "1.24.2-r9", "dpkg", "binary"},
|
||||
{"scanelf", "1.1.6-r0", "dpkg", "binary"},
|
||||
{"alpine-keys", "1.1-r0", "dpkg", "binary"},
|
||||
{"libcrypto1.0", "1.0.2h-r1", "dpkg", "binary"},
|
||||
{"zlib", "1.2.8-r2", "dpkg", "binary"},
|
||||
{"musl-utils", "1.1.14-r10", "dpkg", "binary"},
|
||||
{"alpine-baselayout", "3.0.3-r0", "dpkg", "binary"},
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
@ -37,45 +37,59 @@ var (
|
||||
|
||||
type lister struct{}
|
||||
|
||||
func (l lister) RequiredFilenames() []string {
|
||||
return []string{"var/lib/dpkg/status"}
|
||||
}
|
||||
|
||||
func init() {
|
||||
featurefmt.RegisterLister("dpkg", "1.0", &lister{})
|
||||
}
|
||||
|
||||
func valid(pkg *database.Feature) bool {
|
||||
return pkg.Name != "" && pkg.Version != ""
|
||||
}
|
||||
|
||||
func addSourcePackage(pkg *database.Feature) {
|
||||
if pkg.SourceName == "" {
|
||||
pkg.SourceName = pkg.Name
|
||||
}
|
||||
|
||||
if pkg.SourceVersion == "" {
|
||||
pkg.SourceVersion = pkg.Version
|
||||
}
|
||||
}
|
||||
|
||||
func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
|
||||
f, hasFile := files["var/lib/dpkg/status"]
|
||||
if !hasFile {
|
||||
return []database.Feature{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
pkg = database.Feature{VersionFormat: dpkg.ParserName}
|
||||
pkgs = mapset.NewSet()
|
||||
err error
|
||||
)
|
||||
|
||||
packages := mapset.NewSet()
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(f)))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "Package: ") {
|
||||
// Package line
|
||||
// Defines the name of the package
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
pkg.Name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
|
||||
pkg.Version = ""
|
||||
binary, source := parseDpkgDB(scanner)
|
||||
if binary != nil {
|
||||
packages.Add(*binary)
|
||||
}
|
||||
|
||||
if source != nil {
|
||||
packages.Add(*source)
|
||||
}
|
||||
}
|
||||
|
||||
return database.ConvertFeatureSetToFeatures(packages), nil
|
||||
}
|
||||
|
||||
// parseDpkgDB consumes the status file scanner exactly one package info, until
|
||||
// EOF or empty space, and generate the parsed packages from it.
|
||||
func parseDpkgDB(scanner *bufio.Scanner) (binaryPackage *database.Feature, sourcePackage *database.Feature) {
|
||||
var (
|
||||
name string
|
||||
version string
|
||||
sourceName string
|
||||
sourceVersion string
|
||||
)
|
||||
|
||||
for {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "Package: ") {
|
||||
name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
|
||||
} else if strings.HasPrefix(line, "Source: ") {
|
||||
// Source line (Optional)
|
||||
// Gives the name of the source package
|
||||
@ -87,14 +101,9 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
|
||||
md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n)
|
||||
}
|
||||
|
||||
pkg.SourceName = md["name"]
|
||||
sourceName = md["name"]
|
||||
if md["version"] != "" {
|
||||
version := md["version"]
|
||||
if err = versionfmt.Valid(dpkg.ParserName, version); err != nil {
|
||||
log.WithError(err).WithField("version", string(line[1])).Warning("could not parse package version. skipping")
|
||||
} else {
|
||||
pkg.SourceVersion = version
|
||||
}
|
||||
sourceVersion = md["version"]
|
||||
}
|
||||
} else if strings.HasPrefix(line, "Version: ") {
|
||||
// Version line
|
||||
@ -102,25 +111,43 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
|
||||
// This version is less important than a version retrieved from a Source line
|
||||
// because the Debian vulnerabilities often skips the epoch from the Version field
|
||||
// which is not present in the Source version, and because +bX revisions don't matter
|
||||
version := strings.TrimPrefix(line, "Version: ")
|
||||
if err = versionfmt.Valid(dpkg.ParserName, version); err != nil {
|
||||
log.WithError(err).WithField("version", string(line[1])).Warning("could not parse package version. skipping")
|
||||
} else {
|
||||
pkg.Version = version
|
||||
}
|
||||
} else if line == "" {
|
||||
pkg = database.Feature{VersionFormat: dpkg.ParserName}
|
||||
version = strings.TrimPrefix(line, "Version: ")
|
||||
}
|
||||
|
||||
if valid(&pkg) {
|
||||
addSourcePackage(&pkg)
|
||||
pkgs.Add(pkg)
|
||||
if !scanner.Scan() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return database.ConvertFeatureSetToFeatures(pkgs), nil
|
||||
}
|
||||
if name != "" && version != "" {
|
||||
if err := versionfmt.Valid(dpkg.ParserName, version); err != nil {
|
||||
log.WithError(err).WithFields(log.Fields{"name": name, "version": version}).Warning("skipped unparseable package")
|
||||
} else {
|
||||
binaryPackage = &database.Feature{name, version, dpkg.ParserName, database.BinaryPackage}
|
||||
}
|
||||
}
|
||||
|
||||
func (l lister) RequiredFilenames() []string {
|
||||
return []string{"var/lib/dpkg/status"}
|
||||
// Source version and names are computed from binary package names and versions
|
||||
// in dpkg.
|
||||
// Source package name:
|
||||
// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n338
|
||||
// Source package version:
|
||||
// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n355
|
||||
if sourceName == "" {
|
||||
sourceName = name
|
||||
}
|
||||
|
||||
if sourceVersion == "" {
|
||||
sourceVersion = version
|
||||
}
|
||||
|
||||
if sourceName != "" && sourceVersion != "" {
|
||||
if err := versionfmt.Valid(dpkg.ParserName, version); err != nil {
|
||||
log.WithError(err).WithFields(log.Fields{"name": name, "version": version}).Warning("skipped unparseable package")
|
||||
} else {
|
||||
sourcePackage = &database.Feature{sourceName, sourceVersion, dpkg.ParserName, database.SourcePackage}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -28,105 +28,168 @@ func TestListFeatures(t *testing.T) {
|
||||
"valid status file",
|
||||
map[string]string{"var/lib/dpkg/status": "dpkg/testdata/valid"},
|
||||
[]database.Feature{
|
||||
{"adduser", "3.116ubuntu1", "adduser", "3.116ubuntu1", dpkg.ParserName},
|
||||
{"apt", "1.6.3ubuntu0.1", "apt", "1.6.3ubuntu0.1", dpkg.ParserName},
|
||||
{"base-files", "10.1ubuntu2.2", "base-files", "10.1ubuntu2.2", dpkg.ParserName},
|
||||
{"base-passwd", "3.5.44", "base-passwd", "3.5.44", dpkg.ParserName},
|
||||
{"bash", "4.4.18-2ubuntu1", "bash", "4.4.18-2ubuntu1", dpkg.ParserName},
|
||||
{"bsdutils", "1:2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"bzip2", "1.0.6-8.1", "bzip2", "1.0.6-8.1", dpkg.ParserName},
|
||||
{"coreutils", "8.28-1ubuntu1", "coreutils", "8.28-1ubuntu1", dpkg.ParserName},
|
||||
{"dash", "0.5.8-2.10", "dash", "0.5.8-2.10", dpkg.ParserName},
|
||||
{"debconf", "1.5.66", "debconf", "1.5.66", dpkg.ParserName},
|
||||
{"debianutils", "4.8.4", "debianutils", "4.8.4", dpkg.ParserName},
|
||||
{"diffutils", "1:3.6-1", "diffutils", "1:3.6-1", dpkg.ParserName},
|
||||
{"dpkg", "1.19.0.5ubuntu2", "dpkg", "1.19.0.5ubuntu2", dpkg.ParserName},
|
||||
{"e2fsprogs", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName},
|
||||
{"fdisk", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"findutils", "4.6.0+git+20170828-2", "findutils", "4.6.0+git+20170828-2", dpkg.ParserName},
|
||||
{"gcc-8-base", "8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2", dpkg.ParserName},
|
||||
{"gpgv", "2.2.4-1ubuntu1.1", "gnupg2", "2.2.4-1ubuntu1.1", dpkg.ParserName},
|
||||
{"grep", "3.1-2", "grep", "3.1-2", dpkg.ParserName},
|
||||
{"gzip", "1.6-5ubuntu1", "gzip", "1.6-5ubuntu1", dpkg.ParserName},
|
||||
{"hostname", "3.20", "hostname", "3.20", dpkg.ParserName},
|
||||
{"init-system-helpers", "1.51", "init-system-helpers", "1.51", dpkg.ParserName},
|
||||
{"libacl1", "2.2.52-3build1", "acl", "2.2.52-3build1", dpkg.ParserName},
|
||||
{"libapt-pkg5.0", "1.6.3ubuntu0.1", "apt", "1.6.3ubuntu0.1", dpkg.ParserName},
|
||||
{"libattr1", "1:2.4.47-2build1", "attr", "1:2.4.47-2build1", dpkg.ParserName},
|
||||
{"libaudit-common", "1:2.8.2-1ubuntu1", "audit", "1:2.8.2-1ubuntu1", dpkg.ParserName},
|
||||
{"libaudit1", "1:2.8.2-1ubuntu1", "audit", "1:2.8.2-1ubuntu1", dpkg.ParserName},
|
||||
{"libblkid1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"libbz2-1.0", "1.0.6-8.1", "bzip2", "1.0.6-8.1", dpkg.ParserName},
|
||||
{"libc-bin", "2.27-3ubuntu1", "glibc", "2.27-3ubuntu1", dpkg.ParserName},
|
||||
{"libc6", "2.27-3ubuntu1", "glibc", "2.27-3ubuntu1", dpkg.ParserName},
|
||||
{"libcap-ng0", "0.7.7-3.1", "libcap-ng", "0.7.7-3.1", dpkg.ParserName},
|
||||
{"libcom-err2", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName},
|
||||
{"libdb5.3", "5.3.28-13.1ubuntu1", "db5.3", "5.3.28-13.1ubuntu1", dpkg.ParserName},
|
||||
{"libdebconfclient0", "0.213ubuntu1", "cdebconf", "0.213ubuntu1", dpkg.ParserName},
|
||||
{"libext2fs2", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName},
|
||||
{"libfdisk1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"libffi6", "3.2.1-8", "libffi", "3.2.1-8", dpkg.ParserName},
|
||||
{"libgcc1", "1:8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2", dpkg.ParserName},
|
||||
{"libgcrypt20", "1.8.1-4ubuntu1.1", "libgcrypt20", "1.8.1-4ubuntu1.1", dpkg.ParserName},
|
||||
{"libgmp10", "2:6.1.2+dfsg-2", "gmp", "2:6.1.2+dfsg-2", dpkg.ParserName},
|
||||
{"libgnutls30", "3.5.18-1ubuntu1", "gnutls28", "3.5.18-1ubuntu1", dpkg.ParserName},
|
||||
{"libgpg-error0", "1.27-6", "libgpg-error", "1.27-6", dpkg.ParserName},
|
||||
{"libhogweed4", "3.4-1", "nettle", "3.4-1", dpkg.ParserName},
|
||||
{"libidn2-0", "2.0.4-1.1build2", "libidn2", "2.0.4-1.1build2", dpkg.ParserName},
|
||||
{"liblz4-1", "0.0~r131-2ubuntu3", "lz4", "0.0~r131-2ubuntu3", dpkg.ParserName},
|
||||
{"liblzma5", "5.2.2-1.3", "xz-utils", "5.2.2-1.3", dpkg.ParserName},
|
||||
{"libmount1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"libncurses5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName},
|
||||
{"libncursesw5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName},
|
||||
{"libnettle6", "3.4-1", "nettle", "3.4-1", dpkg.ParserName},
|
||||
{"libp11-kit0", "0.23.9-2", "p11-kit", "0.23.9-2", dpkg.ParserName},
|
||||
{"libpam-modules", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName},
|
||||
{"libpam-modules-bin", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName},
|
||||
{"libpam-runtime", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName},
|
||||
{"libpam0g", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName},
|
||||
{"libpcre3", "2:8.39-9", "pcre3", "2:8.39-9", dpkg.ParserName},
|
||||
{"libprocps6", "2:3.3.12-3ubuntu1.1", "procps", "2:3.3.12-3ubuntu1.1", dpkg.ParserName},
|
||||
{"libseccomp2", "2.3.1-2.1ubuntu4", "libseccomp", "2.3.1-2.1ubuntu4", dpkg.ParserName},
|
||||
{"libselinux1", "2.7-2build2", "libselinux", "2.7-2build2", dpkg.ParserName},
|
||||
{"libsemanage-common", "2.7-2build2", "libsemanage", "2.7-2build2", dpkg.ParserName},
|
||||
{"libsemanage1", "2.7-2build2", "libsemanage", "2.7-2build2", dpkg.ParserName},
|
||||
{"libsepol1", "2.7-1", "libsepol", "2.7-1", dpkg.ParserName},
|
||||
{"libsmartcols1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"libss2", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName},
|
||||
{"libstdc++6", "8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2", dpkg.ParserName},
|
||||
{"libsystemd0", "237-3ubuntu10.3", "systemd", "237-3ubuntu10.3", dpkg.ParserName},
|
||||
{"libtasn1-6", "4.13-2", "libtasn1-6", "4.13-2", dpkg.ParserName},
|
||||
{"libtinfo5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName},
|
||||
{"libudev1", "237-3ubuntu10.3", "systemd", "237-3ubuntu10.3", dpkg.ParserName},
|
||||
{"libunistring2", "0.9.9-0ubuntu1", "libunistring", "0.9.9-0ubuntu1", dpkg.ParserName},
|
||||
{"libuuid1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"libzstd1", "1.3.3+dfsg-2ubuntu1", "libzstd", "1.3.3+dfsg-2ubuntu1", dpkg.ParserName},
|
||||
{"login", "1:4.5-1ubuntu1", "shadow", "1:4.5-1ubuntu1", dpkg.ParserName},
|
||||
{"lsb-base", "9.20170808ubuntu1", "lsb", "9.20170808ubuntu1", dpkg.ParserName},
|
||||
{"mawk", "1.3.3-17ubuntu3", "mawk", "1.3.3-17ubuntu3", dpkg.ParserName},
|
||||
{"mount", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"ncurses-base", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName},
|
||||
{"ncurses-bin", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName},
|
||||
{"passwd", "1:4.5-1ubuntu1", "shadow", "1:4.5-1ubuntu1", dpkg.ParserName},
|
||||
{"perl-base", "5.26.1-6ubuntu0.2", "perl", "5.26.1-6ubuntu0.2", dpkg.ParserName},
|
||||
{"procps", "2:3.3.12-3ubuntu1.1", "procps", "2:3.3.12-3ubuntu1.1", dpkg.ParserName},
|
||||
{"sed", "4.4-2", "sed", "4.4-2", dpkg.ParserName},
|
||||
{"sensible-utils", "0.0.12", "sensible-utils", "0.0.12", dpkg.ParserName},
|
||||
{"sysvinit-utils", "2.88dsf-59.10ubuntu1", "sysvinit", "2.88dsf-59.10ubuntu1", dpkg.ParserName},
|
||||
{"tar", "1.29b-2", "tar", "1.29b-2", dpkg.ParserName},
|
||||
{"ubuntu-keyring", "2018.02.28", "ubuntu-keyring", "2018.02.28", dpkg.ParserName},
|
||||
{"util-linux", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName},
|
||||
{"zlib1g", "1:1.2.11.dfsg-0ubuntu2", "zlib", "1:1.2.11.dfsg-0ubuntu2", dpkg.ParserName},
|
||||
{"libapt-pkg5.0", "1.6.3ubuntu0.1", "dpkg", "binary"},
|
||||
{"perl-base", "5.26.1-6ubuntu0.2", "dpkg", "binary"},
|
||||
{"libmount1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"perl", "5.26.1-6ubuntu0.2", "dpkg", "source"},
|
||||
{"libgnutls30", "3.5.18-1ubuntu1", "dpkg", "binary"},
|
||||
{"liblzma5", "5.2.2-1.3", "dpkg", "binary"},
|
||||
{"ncurses-bin", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
|
||||
{"lsb", "9.20170808ubuntu1", "dpkg", "source"},
|
||||
{"sed", "4.4-2", "dpkg", "source"},
|
||||
{"libsystemd0", "237-3ubuntu10.3", "dpkg", "binary"},
|
||||
{"procps", "2:3.3.12-3ubuntu1.1", "dpkg", "source"},
|
||||
{"login", "1:4.5-1ubuntu1", "dpkg", "binary"},
|
||||
{"libunistring2", "0.9.9-0ubuntu1", "dpkg", "binary"},
|
||||
{"sed", "4.4-2", "dpkg", "binary"},
|
||||
{"libselinux", "2.7-2build2", "dpkg", "source"},
|
||||
{"libseccomp", "2.3.1-2.1ubuntu4", "dpkg", "source"},
|
||||
{"libss2", "1.44.1-1", "dpkg", "binary"},
|
||||
{"liblz4-1", "0.0~r131-2ubuntu3", "dpkg", "binary"},
|
||||
{"libsemanage1", "2.7-2build2", "dpkg", "binary"},
|
||||
{"libtasn1-6", "4.13-2", "dpkg", "source"},
|
||||
{"libzstd1", "1.3.3+dfsg-2ubuntu1", "dpkg", "binary"},
|
||||
{"fdisk", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"xz-utils", "5.2.2-1.3", "dpkg", "source"},
|
||||
{"lsb-base", "9.20170808ubuntu1", "dpkg", "binary"},
|
||||
{"libpam-modules-bin", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
|
||||
{"dash", "0.5.8-2.10", "dpkg", "binary"},
|
||||
{"gnupg2", "2.2.4-1ubuntu1.1", "dpkg", "source"},
|
||||
{"libfdisk1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"lz4", "0.0~r131-2ubuntu3", "dpkg", "source"},
|
||||
{"libpam0g", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
|
||||
{"libc-bin", "2.27-3ubuntu1", "dpkg", "binary"},
|
||||
{"libcap-ng", "0.7.7-3.1", "dpkg", "source"},
|
||||
{"libcom-err2", "1.44.1-1", "dpkg", "binary"},
|
||||
{"libudev1", "237-3ubuntu10.3", "dpkg", "binary"},
|
||||
{"debconf", "1.5.66", "dpkg", "binary"},
|
||||
{"tar", "1.29b-2", "dpkg", "binary"},
|
||||
{"diffutils", "1:3.6-1", "dpkg", "source"},
|
||||
{"gcc-8", "8-20180414-1ubuntu2", "dpkg", "source"},
|
||||
{"e2fsprogs", "1.44.1-1", "dpkg", "source"},
|
||||
{"bzip2", "1.0.6-8.1", "dpkg", "source"},
|
||||
{"diffutils", "1:3.6-1", "dpkg", "binary"},
|
||||
{"grep", "3.1-2", "dpkg", "binary"},
|
||||
{"libgcc1", "1:8-20180414-1ubuntu2", "dpkg", "binary"},
|
||||
{"bash", "4.4.18-2ubuntu1", "dpkg", "source"},
|
||||
{"libtinfo5", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
|
||||
{"procps", "2:3.3.12-3ubuntu1.1", "dpkg", "binary"},
|
||||
{"bzip2", "1.0.6-8.1", "dpkg", "binary"},
|
||||
{"init-system-helpers", "1.51", "dpkg", "binary"},
|
||||
{"libncursesw5", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
|
||||
{"init-system-helpers", "1.51", "dpkg", "source"},
|
||||
{"libpam-modules", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
|
||||
{"libext2fs2", "1.44.1-1", "dpkg", "binary"},
|
||||
{"libacl1", "2.2.52-3build1", "dpkg", "binary"},
|
||||
{"hostname", "3.20", "dpkg", "binary"},
|
||||
{"libgpg-error", "1.27-6", "dpkg", "source"},
|
||||
{"acl", "2.2.52-3build1", "dpkg", "source"},
|
||||
{"apt", "1.6.3ubuntu0.1", "dpkg", "binary"},
|
||||
{"base-files", "10.1ubuntu2.2", "dpkg", "source"},
|
||||
{"libgpg-error0", "1.27-6", "dpkg", "binary"},
|
||||
{"audit", "1:2.8.2-1ubuntu1", "dpkg", "source"},
|
||||
{"hostname", "3.20", "dpkg", "source"},
|
||||
{"gzip", "1.6-5ubuntu1", "dpkg", "binary"},
|
||||
{"libc6", "2.27-3ubuntu1", "dpkg", "binary"},
|
||||
{"libnettle6", "3.4-1", "dpkg", "binary"},
|
||||
{"sysvinit-utils", "2.88dsf-59.10ubuntu1", "dpkg", "binary"},
|
||||
{"debianutils", "4.8.4", "dpkg", "source"},
|
||||
{"libstdc++6", "8-20180414-1ubuntu2", "dpkg", "binary"},
|
||||
{"libsepol", "2.7-1", "dpkg", "source"},
|
||||
{"libpcre3", "2:8.39-9", "dpkg", "binary"},
|
||||
{"libuuid1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"systemd", "237-3ubuntu10.3", "dpkg", "source"},
|
||||
{"tar", "1.29b-2", "dpkg", "source"},
|
||||
{"ubuntu-keyring", "2018.02.28", "dpkg", "source"},
|
||||
{"passwd", "1:4.5-1ubuntu1", "dpkg", "binary"},
|
||||
{"sysvinit", "2.88dsf-59.10ubuntu1", "dpkg", "source"},
|
||||
{"libidn2-0", "2.0.4-1.1build2", "dpkg", "binary"},
|
||||
{"libhogweed4", "3.4-1", "dpkg", "binary"},
|
||||
{"db5.3", "5.3.28-13.1ubuntu1", "dpkg", "source"},
|
||||
{"sensible-utils", "0.0.12", "dpkg", "source"},
|
||||
{"dpkg", "1.19.0.5ubuntu2", "dpkg", "source"},
|
||||
{"libp11-kit0", "0.23.9-2", "dpkg", "binary"},
|
||||
{"glibc", "2.27-3ubuntu1", "dpkg", "source"},
|
||||
{"mount", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"libsemanage-common", "2.7-2build2", "dpkg", "binary"},
|
||||
{"libblkid1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"libdebconfclient0", "0.213ubuntu1", "dpkg", "binary"},
|
||||
{"libffi", "3.2.1-8", "dpkg", "source"},
|
||||
{"pam", "1.1.8-3.6ubuntu2", "dpkg", "source"},
|
||||
{"bsdutils", "1:2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"libtasn1-6", "4.13-2", "dpkg", "binary"},
|
||||
{"libaudit-common", "1:2.8.2-1ubuntu1", "dpkg", "binary"},
|
||||
{"gpgv", "2.2.4-1ubuntu1.1", "dpkg", "binary"},
|
||||
{"libzstd", "1.3.3+dfsg-2ubuntu1", "dpkg", "source"},
|
||||
{"base-passwd", "3.5.44", "dpkg", "source"},
|
||||
{"adduser", "3.116ubuntu1", "dpkg", "binary"},
|
||||
{"libattr1", "1:2.4.47-2build1", "dpkg", "binary"},
|
||||
{"libncurses5", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
|
||||
{"coreutils", "8.28-1ubuntu1", "dpkg", "binary"},
|
||||
{"base-passwd", "3.5.44", "dpkg", "binary"},
|
||||
{"ubuntu-keyring", "2018.02.28", "dpkg", "binary"},
|
||||
{"adduser", "3.116ubuntu1", "dpkg", "source"},
|
||||
{"libsmartcols1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"libunistring", "0.9.9-0ubuntu1", "dpkg", "source"},
|
||||
{"mawk", "1.3.3-17ubuntu3", "dpkg", "source"},
|
||||
{"coreutils", "8.28-1ubuntu1", "dpkg", "source"},
|
||||
{"attr", "1:2.4.47-2build1", "dpkg", "source"},
|
||||
{"gmp", "2:6.1.2+dfsg-2", "dpkg", "source"},
|
||||
{"libsemanage", "2.7-2build2", "dpkg", "source"},
|
||||
{"libselinux1", "2.7-2build2", "dpkg", "binary"},
|
||||
{"libseccomp2", "2.3.1-2.1ubuntu4", "dpkg", "binary"},
|
||||
{"zlib1g", "1:1.2.11.dfsg-0ubuntu2", "dpkg", "binary"},
|
||||
{"dash", "0.5.8-2.10", "dpkg", "source"},
|
||||
{"gnutls28", "3.5.18-1ubuntu1", "dpkg", "source"},
|
||||
{"libpam-runtime", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
|
||||
{"libgcrypt20", "1.8.1-4ubuntu1.1", "dpkg", "source"},
|
||||
{"sensible-utils", "0.0.12", "dpkg", "binary"},
|
||||
{"p11-kit", "0.23.9-2", "dpkg", "source"},
|
||||
{"ncurses-base", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
|
||||
{"e2fsprogs", "1.44.1-1", "dpkg", "binary"},
|
||||
{"libgcrypt20", "1.8.1-4ubuntu1.1", "dpkg", "binary"},
|
||||
{"libprocps6", "2:3.3.12-3ubuntu1.1", "dpkg", "binary"},
|
||||
{"debconf", "1.5.66", "dpkg", "source"},
|
||||
{"gcc-8-base", "8-20180414-1ubuntu2", "dpkg", "binary"},
|
||||
{"base-files", "10.1ubuntu2.2", "dpkg", "binary"},
|
||||
{"libbz2-1.0", "1.0.6-8.1", "dpkg", "binary"},
|
||||
{"grep", "3.1-2", "dpkg", "source"},
|
||||
{"bash", "4.4.18-2ubuntu1", "dpkg", "binary"},
|
||||
{"libgmp10", "2:6.1.2+dfsg-2", "dpkg", "binary"},
|
||||
{"shadow", "1:4.5-1ubuntu1", "dpkg", "source"},
|
||||
{"libidn2", "2.0.4-1.1build2", "dpkg", "source"},
|
||||
{"gzip", "1.6-5ubuntu1", "dpkg", "source"},
|
||||
{"util-linux", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
|
||||
{"libaudit1", "1:2.8.2-1ubuntu1", "dpkg", "binary"},
|
||||
{"libsepol1", "2.7-1", "dpkg", "binary"},
|
||||
{"pcre3", "2:8.39-9", "dpkg", "source"},
|
||||
{"apt", "1.6.3ubuntu0.1", "dpkg", "source"},
|
||||
{"nettle", "3.4-1", "dpkg", "source"},
|
||||
{"util-linux", "2.31.1-0.4ubuntu3.1", "dpkg", "source"},
|
||||
{"libcap-ng0", "0.7.7-3.1", "dpkg", "binary"},
|
||||
{"debianutils", "4.8.4", "dpkg", "binary"},
|
||||
{"ncurses", "6.1-1ubuntu1.18.04", "dpkg", "source"},
|
||||
{"libffi6", "3.2.1-8", "dpkg", "binary"},
|
||||
{"cdebconf", "0.213ubuntu1", "dpkg", "source"},
|
||||
{"findutils", "4.6.0+git+20170828-2", "dpkg", "source"},
|
||||
{"libdb5.3", "5.3.28-13.1ubuntu1", "dpkg", "binary"},
|
||||
{"zlib", "1:1.2.11.dfsg-0ubuntu2", "dpkg", "source"},
|
||||
{"findutils", "4.6.0+git+20170828-2", "dpkg", "binary"},
|
||||
{"dpkg", "1.19.0.5ubuntu2", "dpkg", "binary"},
|
||||
{"mawk", "1.3.3-17ubuntu3", "dpkg", "binary"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"corrupted status file",
|
||||
map[string]string{"var/lib/dpkg/status": "dpkg/testdata/corrupted"},
|
||||
[]database.Feature{
|
||||
{"libpam-runtime", "1.1.8-3.1ubuntu3", "pam", "1.1.8-3.1ubuntu3", dpkg.ParserName},
|
||||
{"libpam-modules-bin", "1.1.8-3.1ubuntu3", "pam", "1.1.8-3.1ubuntu3", dpkg.ParserName},
|
||||
{"makedev", "2.3.1-93ubuntu1", "makedev", "2.3.1-93ubuntu1", dpkg.ParserName},
|
||||
{"libgcc1", "1:5.1.1-12ubuntu1", "gcc-5", "5.1.1-12ubuntu1", dpkg.ParserName},
|
||||
{"libpam-modules-bin", "1.1.8-3.1ubuntu3", "dpkg", "binary"},
|
||||
{"gcc-5", "5.1.1-12ubuntu1", "dpkg", "source"},
|
||||
{"makedev", "2.3.1-93ubuntu1", "dpkg", "binary"},
|
||||
{"libgcc1", "1:5.1.1-12ubuntu1", "dpkg", "binary"},
|
||||
{"pam", "1.1.8-3.1ubuntu3", "dpkg", "source"},
|
||||
{"makedev", "2.3.1-93ubuntu1", "dpkg", "source"},
|
||||
{"libpam-runtime", "1.1.8-3.1ubuntu3", "dpkg", "binary"},
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
@ -45,6 +45,10 @@ func init() {
|
||||
featurefmt.RegisterLister("rpm", "1.0", &lister{})
|
||||
}
|
||||
|
||||
func (l lister) RequiredFilenames() []string {
|
||||
return []string{"var/lib/rpm/Packages"}
|
||||
}
|
||||
|
||||
func isIgnored(packageName string) bool {
|
||||
for _, pkg := range ignoredPackages {
|
||||
if pkg == packageName {
|
||||
@ -55,12 +59,6 @@ func isIgnored(packageName string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func valid(pkg *database.Feature) bool {
|
||||
return pkg.Name != "" && pkg.Version != "" &&
|
||||
((pkg.SourceName == "" && pkg.SourceVersion != "") ||
|
||||
(pkg.SourceName != "" && pkg.SourceVersion != ""))
|
||||
}
|
||||
|
||||
func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
|
||||
f, hasFile := files["var/lib/rpm/Packages"]
|
||||
if !hasFile {
|
||||
@ -84,7 +82,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
|
||||
// Extract binary package names because RHSA refers to binary package names.
|
||||
out, err := exec.Command("rpm", "--dbpath", tmpDir, "-qa", "--qf", "%{NAME} %{EPOCH}:%{VERSION}-%{RELEASE} %{SOURCERPM}\n").CombinedOutput()
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("output", string(out)).Error("could not query RPM")
|
||||
log.WithError(err).WithField("output", string(out)).Error("failed to query RPM")
|
||||
// Do not bubble up because we probably won't be able to fix it,
|
||||
// the database must be corrupted
|
||||
return []database.Feature{}, nil
|
||||
@ -93,39 +91,51 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
|
||||
packages := mapset.NewSet()
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(out)))
|
||||
for scanner.Scan() {
|
||||
line := strings.Split(scanner.Text(), " ")
|
||||
if len(line) != 3 {
|
||||
// We may see warnings on some RPM versions:
|
||||
// "warning: Generating 12 missing index(es), please wait..."
|
||||
continue
|
||||
rpmPackage, srpmPackage := parseRPMOutput(scanner.Text())
|
||||
if rpmPackage != nil {
|
||||
packages.Add(*rpmPackage)
|
||||
}
|
||||
|
||||
if isIgnored(line[0]) {
|
||||
continue
|
||||
}
|
||||
|
||||
pkg := database.Feature{Name: line[0], VersionFormat: rpm.ParserName}
|
||||
pkg.Version = strings.Replace(line[1], "(none):", "", -1)
|
||||
if err := versionfmt.Valid(rpm.ParserName, pkg.Version); err != nil {
|
||||
log.WithError(err).WithField("version", line[1]).Warning("skipped unparseable package")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := parseSourceRPM(line[2], &pkg); err != nil {
|
||||
log.WithError(err).WithField("sourcerpm", line[2]).Warning("skipped unparseable package")
|
||||
continue
|
||||
}
|
||||
|
||||
if valid(&pkg) {
|
||||
packages.Add(pkg)
|
||||
if srpmPackage != nil {
|
||||
packages.Add(*srpmPackage)
|
||||
}
|
||||
}
|
||||
|
||||
return database.ConvertFeatureSetToFeatures(packages), nil
|
||||
}
|
||||
|
||||
func (l lister) RequiredFilenames() []string {
|
||||
return []string{"var/lib/rpm/Packages"}
|
||||
func parseRPMOutput(raw string) (rpmPackage *database.Feature, srpmPackage *database.Feature) {
|
||||
line := strings.Split(raw, " ")
|
||||
if len(line) != 3 {
|
||||
// We may see warnings on some RPM versions:
|
||||
// "warning: Generating 12 missing index(es), please wait..."
|
||||
return
|
||||
}
|
||||
|
||||
if isIgnored(line[0]) {
|
||||
return
|
||||
}
|
||||
|
||||
name, version, srpm := line[0], strings.Replace(line[1], "(none):", "", -1), line[2]
|
||||
if err := versionfmt.Valid(rpm.ParserName, version); err != nil {
|
||||
log.WithError(err).WithFields(log.Fields{"name": name, "version": version}).Warning("skipped unparseable package")
|
||||
return
|
||||
}
|
||||
|
||||
rpmPackage = &database.Feature{name, version, rpm.ParserName, database.BinaryPackage}
|
||||
srpmName, srpmVersion, srpmRelease, _, err := parseSourceRPM(srpm)
|
||||
if err != nil {
|
||||
log.WithError(err).WithFields(log.Fields{"name": name, "sourcerpm": srpm}).Warning("skipped unparseable package")
|
||||
return
|
||||
}
|
||||
|
||||
srpmVersion = srpmVersion + "-" + srpmRelease
|
||||
if err = versionfmt.Valid(rpm.ParserName, srpmVersion); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
srpmPackage = &database.Feature{srpmName, srpmVersion, rpm.ParserName, database.SourcePackage}
|
||||
return
|
||||
}
|
||||
|
||||
type rpmParserState string
|
||||
@ -140,11 +150,9 @@ const (
|
||||
|
||||
// parseSourceRPM parses the source rpm package representation string
|
||||
// http://ftp.rpm.org/max-rpm/ch-rpm-file-format.html
|
||||
func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
|
||||
func parseSourceRPM(sourceRPM string) (name string, version string, release string, architecture string, err error) {
|
||||
state := parseRPM
|
||||
previousCheckPoint := len(sourceRPM)
|
||||
release := ""
|
||||
version := ""
|
||||
for i := len(sourceRPM) - 1; i >= 0; i-- {
|
||||
switch state {
|
||||
case parseRPM:
|
||||
@ -153,16 +161,18 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
|
||||
packageType := strutil.Substring(sourceRPM, i+1, len(sourceRPM))
|
||||
previousCheckPoint = i
|
||||
if packageType != "rpm" {
|
||||
return fmt.Errorf("unexpected package type, expect: 'rpm', got: '%s'", packageType)
|
||||
err = fmt.Errorf("unexpected package type, expect: 'rpm', got: '%s'", packageType)
|
||||
return
|
||||
}
|
||||
}
|
||||
case parseArchitecture:
|
||||
if string(sourceRPM[i]) == "." {
|
||||
state = parseRelease
|
||||
architecture := strutil.Substring(sourceRPM, i+1, previousCheckPoint)
|
||||
architecture = strutil.Substring(sourceRPM, i+1, previousCheckPoint)
|
||||
previousCheckPoint = i
|
||||
if architecture != "src" && architecture != "nosrc" {
|
||||
return fmt.Errorf("unexpected package architecture, expect: 'src' or 'nosrc', got: '%s'", architecture)
|
||||
err = fmt.Errorf("unexpected package architecture, expect: 'src' or 'nosrc', got: '%s'", architecture)
|
||||
return
|
||||
}
|
||||
}
|
||||
case parseRelease:
|
||||
@ -171,7 +181,8 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
|
||||
release = strutil.Substring(sourceRPM, i+1, previousCheckPoint)
|
||||
previousCheckPoint = i
|
||||
if release == "" {
|
||||
return fmt.Errorf("unexpected package release, expect: not empty")
|
||||
err = fmt.Errorf("unexpected package release, expect: not empty")
|
||||
return
|
||||
}
|
||||
}
|
||||
case parseVersion:
|
||||
@ -181,7 +192,8 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
|
||||
version = strutil.Substring(sourceRPM, i+1, previousCheckPoint)
|
||||
previousCheckPoint = i
|
||||
if version == "" {
|
||||
return fmt.Errorf("unexpected package version, expect: not empty")
|
||||
err = fmt.Errorf("unexpected package version, expect: not empty")
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
@ -189,20 +201,15 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
|
||||
}
|
||||
|
||||
if state != terminate {
|
||||
return fmt.Errorf("unexpected termination while parsing '%s'", state)
|
||||
err = fmt.Errorf("unexpected termination while parsing '%s'", state)
|
||||
return
|
||||
}
|
||||
|
||||
concatVersion := version + "-" + release
|
||||
if err := versionfmt.Valid(rpm.ParserName, concatVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := strutil.Substring(sourceRPM, 0, previousCheckPoint)
|
||||
name = strutil.Substring(sourceRPM, 0, previousCheckPoint)
|
||||
if name == "" {
|
||||
return fmt.Errorf("unexpected package name, expect: not empty")
|
||||
err = fmt.Errorf("unexpected package name, expect: not empty")
|
||||
return
|
||||
}
|
||||
|
||||
pkg.SourceName = name
|
||||
pkg.SourceVersion = concatVersion
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
@ -25,179 +25,307 @@ import (
|
||||
)
|
||||
|
||||
var expectedBigCaseInfo = []database.Feature{
|
||||
{"publicsuffix-list-dafsa", "20180514-1.fc28", "publicsuffix-list", "20180514-1.fc28", rpm.ParserName},
|
||||
{"libreport-filesystem", "2.9.5-1.fc28", "libreport", "2.9.5-1.fc28", rpm.ParserName},
|
||||
{"fedora-gpg-keys", "28-5", "fedora-repos", "28-5", rpm.ParserName},
|
||||
{"fedora-release", "28-2", "fedora-release", "28-2", rpm.ParserName},
|
||||
{"filesystem", "3.8-2.fc28", "filesystem", "3.8-2.fc28", rpm.ParserName},
|
||||
{"tzdata", "2018e-1.fc28", "tzdata", "2018e-1.fc28", rpm.ParserName},
|
||||
{"pcre2", "10.31-10.fc28", "pcre2", "10.31-10.fc28", rpm.ParserName},
|
||||
{"glibc-minimal-langpack", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName},
|
||||
{"glibc-common", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName},
|
||||
{"bash", "4.4.23-1.fc28", "bash", "4.4.23-1.fc28", rpm.ParserName},
|
||||
{"zlib", "1.2.11-8.fc28", "zlib", "1.2.11-8.fc28", rpm.ParserName},
|
||||
{"bzip2-libs", "1.0.6-26.fc28", "bzip2", "1.0.6-26.fc28", rpm.ParserName},
|
||||
{"libcap", "2.25-9.fc28", "libcap", "2.25-9.fc28", rpm.ParserName},
|
||||
{"libgpg-error", "1.31-1.fc28", "libgpg-error", "1.31-1.fc28", rpm.ParserName},
|
||||
{"libzstd", "1.3.5-1.fc28", "zstd", "1.3.5-1.fc28", rpm.ParserName},
|
||||
{"expat", "2.2.5-3.fc28", "expat", "2.2.5-3.fc28", rpm.ParserName},
|
||||
{"nss-util", "3.38.0-1.0.fc28", "nss-util", "3.38.0-1.0.fc28", rpm.ParserName},
|
||||
{"libcom_err", "1.44.2-0.fc28", "e2fsprogs", "1.44.2-0.fc28", rpm.ParserName},
|
||||
{"libffi", "3.1-16.fc28", "libffi", "3.1-16.fc28", rpm.ParserName},
|
||||
{"libgcrypt", "1.8.3-1.fc28", "libgcrypt", "1.8.3-1.fc28", rpm.ParserName},
|
||||
{"libxml2", "2.9.8-4.fc28", "libxml2", "2.9.8-4.fc28", rpm.ParserName},
|
||||
{"libacl", "2.2.53-1.fc28", "acl", "2.2.53-1.fc28", rpm.ParserName},
|
||||
{"sed", "4.5-1.fc28", "sed", "4.5-1.fc28", rpm.ParserName},
|
||||
{"libmount", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName},
|
||||
{"p11-kit", "0.23.12-1.fc28", "p11-kit", "0.23.12-1.fc28", rpm.ParserName},
|
||||
{"libidn2", "2.0.5-1.fc28", "libidn2", "2.0.5-1.fc28", rpm.ParserName},
|
||||
{"libcap-ng", "0.7.9-4.fc28", "libcap-ng", "0.7.9-4.fc28", rpm.ParserName},
|
||||
{"lz4-libs", "1.8.1.2-4.fc28", "lz4", "1.8.1.2-4.fc28", rpm.ParserName},
|
||||
{"libassuan", "2.5.1-3.fc28", "libassuan", "2.5.1-3.fc28", rpm.ParserName},
|
||||
{"keyutils-libs", "1.5.10-6.fc28", "keyutils", "1.5.10-6.fc28", rpm.ParserName},
|
||||
{"glib2", "2.56.1-4.fc28", "glib2", "2.56.1-4.fc28", rpm.ParserName},
|
||||
{"systemd-libs", "238-9.git0e0aa59.fc28", "systemd", "238-9.git0e0aa59.fc28", rpm.ParserName},
|
||||
{"dbus-libs", "1:1.12.10-1.fc28", "dbus", "1.12.10-1.fc28", rpm.ParserName},
|
||||
{"libtasn1", "4.13-2.fc28", "libtasn1", "4.13-2.fc28", rpm.ParserName},
|
||||
{"ca-certificates", "2018.2.24-1.0.fc28", "ca-certificates", "2018.2.24-1.0.fc28", rpm.ParserName},
|
||||
{"libarchive", "3.3.1-4.fc28", "libarchive", "3.3.1-4.fc28", rpm.ParserName},
|
||||
{"openssl", "1:1.1.0h-3.fc28", "openssl", "1.1.0h-3.fc28", rpm.ParserName},
|
||||
{"libusbx", "1.0.22-1.fc28", "libusbx", "1.0.22-1.fc28", rpm.ParserName},
|
||||
{"libsemanage", "2.8-2.fc28", "libsemanage", "2.8-2.fc28", rpm.ParserName},
|
||||
{"libutempter", "1.1.6-14.fc28", "libutempter", "1.1.6-14.fc28", rpm.ParserName},
|
||||
{"mpfr", "3.1.6-1.fc28", "mpfr", "3.1.6-1.fc28", rpm.ParserName},
|
||||
{"gnutls", "3.6.3-4.fc28", "gnutls", "3.6.3-4.fc28", rpm.ParserName},
|
||||
{"gzip", "1.9-3.fc28", "gzip", "1.9-3.fc28", rpm.ParserName},
|
||||
{"acl", "2.2.53-1.fc28", "acl", "2.2.53-1.fc28", rpm.ParserName},
|
||||
{"nss-softokn-freebl", "3.38.0-1.0.fc28", "nss-softokn", "3.38.0-1.0.fc28", rpm.ParserName},
|
||||
{"nss", "3.38.0-1.0.fc28", "nss", "3.38.0-1.0.fc28", rpm.ParserName},
|
||||
{"libmetalink", "0.1.3-6.fc28", "libmetalink", "0.1.3-6.fc28", rpm.ParserName},
|
||||
{"libdb-utils", "5.3.28-30.fc28", "libdb", "5.3.28-30.fc28", rpm.ParserName},
|
||||
{"file-libs", "5.33-7.fc28", "file", "5.33-7.fc28", rpm.ParserName},
|
||||
{"libsss_idmap", "1.16.3-2.fc28", "sssd", "1.16.3-2.fc28", rpm.ParserName},
|
||||
{"libsigsegv", "2.11-5.fc28", "libsigsegv", "2.11-5.fc28", rpm.ParserName},
|
||||
{"krb5-libs", "1.16.1-13.fc28", "krb5", "1.16.1-13.fc28", rpm.ParserName},
|
||||
{"libnsl2", "1.2.0-2.20180605git4a062cf.fc28", "libnsl2", "1.2.0-2.20180605git4a062cf.fc28", rpm.ParserName},
|
||||
{"python3-pip", "9.0.3-2.fc28", "python-pip", "9.0.3-2.fc28", rpm.ParserName},
|
||||
{"python3", "3.6.6-1.fc28", "python3", "3.6.6-1.fc28", rpm.ParserName},
|
||||
{"pam", "1.3.1-1.fc28", "pam", "1.3.1-1.fc28", rpm.ParserName},
|
||||
{"python3-gobject-base", "3.28.3-1.fc28", "pygobject3", "3.28.3-1.fc28", rpm.ParserName},
|
||||
{"python3-smartcols", "0.3.0-2.fc28", "python-smartcols", "0.3.0-2.fc28", rpm.ParserName},
|
||||
{"python3-iniparse", "0.4-30.fc28", "python-iniparse", "0.4-30.fc28", rpm.ParserName},
|
||||
{"openldap", "2.4.46-3.fc28", "openldap", "2.4.46-3.fc28", rpm.ParserName},
|
||||
{"libseccomp", "2.3.3-2.fc28", "libseccomp", "2.3.3-2.fc28", rpm.ParserName},
|
||||
{"npth", "1.5-4.fc28", "npth", "1.5-4.fc28", rpm.ParserName},
|
||||
{"gpgme", "1.10.0-4.fc28", "gpgme", "1.10.0-4.fc28", rpm.ParserName},
|
||||
{"json-c", "0.13.1-2.fc28", "json-c", "0.13.1-2.fc28", rpm.ParserName},
|
||||
{"libyaml", "0.1.7-5.fc28", "libyaml", "0.1.7-5.fc28", rpm.ParserName},
|
||||
{"libpkgconf", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName},
|
||||
{"pkgconf-pkg-config", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName},
|
||||
{"iptables-libs", "1.6.2-3.fc28", "iptables", "1.6.2-3.fc28", rpm.ParserName},
|
||||
{"device-mapper-libs", "1.02.146-5.fc28", "lvm2", "2.02.177-5.fc28", rpm.ParserName},
|
||||
{"systemd-pam", "238-9.git0e0aa59.fc28", "systemd", "238-9.git0e0aa59.fc28", rpm.ParserName},
|
||||
{"systemd", "238-9.git0e0aa59.fc28", "systemd", "238-9.git0e0aa59.fc28", rpm.ParserName},
|
||||
{"elfutils-default-yama-scope", "0.173-1.fc28", "elfutils", "0.173-1.fc28", rpm.ParserName},
|
||||
{"libcurl", "7.59.0-6.fc28", "curl", "7.59.0-6.fc28", rpm.ParserName},
|
||||
{"python3-librepo", "1.8.1-7.fc28", "librepo", "1.8.1-7.fc28", rpm.ParserName},
|
||||
{"rpm-plugin-selinux", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"rpm", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"libdnf", "0.11.1-3.fc28", "libdnf", "0.11.1-3.fc28", rpm.ParserName},
|
||||
{"rpm-build-libs", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"python3-rpm", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"dnf", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName},
|
||||
{"deltarpm", "3.6-25.fc28", "deltarpm", "3.6-25.fc28", rpm.ParserName},
|
||||
{"sssd-client", "1.16.3-2.fc28", "sssd", "1.16.3-2.fc28", rpm.ParserName},
|
||||
{"cracklib-dicts", "2.9.6-13.fc28", "cracklib", "2.9.6-13.fc28", rpm.ParserName},
|
||||
{"tar", "2:1.30-3.fc28", "tar", "1.30-3.fc28", rpm.ParserName},
|
||||
{"diffutils", "3.6-4.fc28", "diffutils", "3.6-4.fc28", rpm.ParserName},
|
||||
{"langpacks-en", "1.0-12.fc28", "langpacks", "1.0-12.fc28", rpm.ParserName},
|
||||
{"libgcc", "8.1.1-5.fc28", "gcc", "8.1.1-5.fc28", rpm.ParserName},
|
||||
{"pkgconf-m4", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName},
|
||||
{"dnf-conf", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName},
|
||||
{"fedora-repos", "28-5", "fedora-repos", "28-5", rpm.ParserName},
|
||||
{"setup", "2.11.4-1.fc28", "setup", "2.11.4-1.fc28", rpm.ParserName},
|
||||
{"basesystem", "11-5.fc28", "basesystem", "11-5.fc28", rpm.ParserName},
|
||||
{"ncurses-base", "6.1-5.20180224.fc28", "ncurses", "6.1-5.20180224.fc28", rpm.ParserName},
|
||||
{"libselinux", "2.8-1.fc28", "libselinux", "2.8-1.fc28", rpm.ParserName},
|
||||
{"ncurses-libs", "6.1-5.20180224.fc28", "ncurses", "6.1-5.20180224.fc28", rpm.ParserName},
|
||||
{"glibc", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName},
|
||||
{"libsepol", "2.8-1.fc28", "libsepol", "2.8-1.fc28", rpm.ParserName},
|
||||
{"xz-libs", "5.2.4-2.fc28", "xz", "5.2.4-2.fc28", rpm.ParserName},
|
||||
{"info", "6.5-4.fc28", "texinfo", "6.5-4.fc28", rpm.ParserName},
|
||||
{"libdb", "5.3.28-30.fc28", "libdb", "5.3.28-30.fc28", rpm.ParserName},
|
||||
{"elfutils-libelf", "0.173-1.fc28", "elfutils", "0.173-1.fc28", rpm.ParserName},
|
||||
{"popt", "1.16-14.fc28", "popt", "1.16-14.fc28", rpm.ParserName},
|
||||
{"nspr", "4.19.0-1.fc28", "nspr", "4.19.0-1.fc28", rpm.ParserName},
|
||||
{"libxcrypt", "4.1.2-1.fc28", "libxcrypt", "4.1.2-1.fc28", rpm.ParserName},
|
||||
{"lua-libs", "5.3.4-10.fc28", "lua", "5.3.4-10.fc28", rpm.ParserName},
|
||||
{"libuuid", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName},
|
||||
{"readline", "7.0-11.fc28", "readline", "7.0-11.fc28", rpm.ParserName},
|
||||
{"libattr", "2.4.48-3.fc28", "attr", "2.4.48-3.fc28", rpm.ParserName},
|
||||
{"coreutils-single", "8.29-7.fc28", "coreutils", "8.29-7.fc28", rpm.ParserName},
|
||||
{"libblkid", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName},
|
||||
{"gmp", "1:6.1.2-7.fc28", "gmp", "6.1.2-7.fc28", rpm.ParserName},
|
||||
{"libunistring", "0.9.10-1.fc28", "libunistring", "0.9.10-1.fc28", rpm.ParserName},
|
||||
{"sqlite-libs", "3.22.0-4.fc28", "sqlite", "3.22.0-4.fc28", rpm.ParserName},
|
||||
{"audit-libs", "2.8.4-2.fc28", "audit", "2.8.4-2.fc28", rpm.ParserName},
|
||||
{"chkconfig", "1.10-4.fc28", "chkconfig", "1.10-4.fc28", rpm.ParserName},
|
||||
{"libsmartcols", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName},
|
||||
{"pcre", "8.42-3.fc28", "pcre", "8.42-3.fc28", rpm.ParserName},
|
||||
{"grep", "3.1-5.fc28", "grep", "3.1-5.fc28", rpm.ParserName},
|
||||
{"crypto-policies", "20180425-5.git6ad4018.fc28", "crypto-policies", "20180425-5.git6ad4018.fc28", rpm.ParserName},
|
||||
{"gdbm-libs", "1:1.14.1-4.fc28", "gdbm", "1.14.1-4.fc28", rpm.ParserName},
|
||||
{"p11-kit-trust", "0.23.12-1.fc28", "p11-kit", "0.23.12-1.fc28", rpm.ParserName},
|
||||
{"openssl-libs", "1:1.1.0h-3.fc28", "openssl", "1.1.0h-3.fc28", rpm.ParserName},
|
||||
{"ima-evm-utils", "1.1-2.fc28", "ima-evm-utils", "1.1-2.fc28", rpm.ParserName},
|
||||
{"gdbm", "1:1.14.1-4.fc28", "gdbm", "1.14.1-4.fc28", rpm.ParserName},
|
||||
{"gobject-introspection", "1.56.1-1.fc28", "gobject-introspection", "1.56.1-1.fc28", rpm.ParserName},
|
||||
{"shadow-utils", "2:4.6-1.fc28", "shadow-utils", "4.6-1.fc28", rpm.ParserName},
|
||||
{"libpsl", "0.20.2-2.fc28", "libpsl", "0.20.2-2.fc28", rpm.ParserName},
|
||||
{"nettle", "3.4-2.fc28", "nettle", "3.4-2.fc28", rpm.ParserName},
|
||||
{"libfdisk", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName},
|
||||
{"cracklib", "2.9.6-13.fc28", "cracklib", "2.9.6-13.fc28", rpm.ParserName},
|
||||
{"libcomps", "0.1.8-11.fc28", "libcomps", "0.1.8-11.fc28", rpm.ParserName},
|
||||
{"nss-softokn", "3.38.0-1.0.fc28", "nss-softokn", "3.38.0-1.0.fc28", rpm.ParserName},
|
||||
{"nss-sysinit", "3.38.0-1.0.fc28", "nss", "3.38.0-1.0.fc28", rpm.ParserName},
|
||||
{"libksba", "1.3.5-7.fc28", "libksba", "1.3.5-7.fc28", rpm.ParserName},
|
||||
{"kmod-libs", "25-2.fc28", "kmod", "25-2.fc28", rpm.ParserName},
|
||||
{"libsss_nss_idmap", "1.16.3-2.fc28", "sssd", "1.16.3-2.fc28", rpm.ParserName},
|
||||
{"libverto", "0.3.0-5.fc28", "libverto", "0.3.0-5.fc28", rpm.ParserName},
|
||||
{"gawk", "4.2.1-1.fc28", "gawk", "4.2.1-1.fc28", rpm.ParserName},
|
||||
{"libtirpc", "1.0.3-3.rc2.fc28", "libtirpc", "1.0.3-3.rc2.fc28", rpm.ParserName},
|
||||
{"python3-libs", "3.6.6-1.fc28", "python3", "3.6.6-1.fc28", rpm.ParserName},
|
||||
{"python3-setuptools", "39.2.0-6.fc28", "python-setuptools", "39.2.0-6.fc28", rpm.ParserName},
|
||||
{"libpwquality", "1.4.0-7.fc28", "libpwquality", "1.4.0-7.fc28", rpm.ParserName},
|
||||
{"util-linux", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName},
|
||||
{"python3-libcomps", "0.1.8-11.fc28", "libcomps", "0.1.8-11.fc28", rpm.ParserName},
|
||||
{"python3-six", "1.11.0-3.fc28", "python-six", "1.11.0-3.fc28", rpm.ParserName},
|
||||
{"cyrus-sasl-lib", "2.1.27-0.2rc7.fc28", "cyrus-sasl", "2.1.27-0.2rc7.fc28", rpm.ParserName},
|
||||
{"libssh", "0.8.2-1.fc28", "libssh", "0.8.2-1.fc28", rpm.ParserName},
|
||||
{"qrencode-libs", "3.4.4-5.fc28", "qrencode", "3.4.4-5.fc28", rpm.ParserName},
|
||||
{"gnupg2", "2.2.8-1.fc28", "gnupg2", "2.2.8-1.fc28", rpm.ParserName},
|
||||
{"python3-gpg", "1.10.0-4.fc28", "gpgme", "1.10.0-4.fc28", rpm.ParserName},
|
||||
{"libargon2", "20161029-5.fc28", "argon2", "20161029-5.fc28", rpm.ParserName},
|
||||
{"libmodulemd", "1.6.2-2.fc28", "libmodulemd", "1.6.2-2.fc28", rpm.ParserName},
|
||||
{"pkgconf", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName},
|
||||
{"libpcap", "14:1.9.0-1.fc28", "libpcap", "1.9.0-1.fc28", rpm.ParserName},
|
||||
{"device-mapper", "1.02.146-5.fc28", "lvm2", "2.02.177-5.fc28", rpm.ParserName},
|
||||
{"cryptsetup-libs", "2.0.4-1.fc28", "cryptsetup", "2.0.4-1.fc28", rpm.ParserName},
|
||||
{"elfutils-libs", "0.173-1.fc28", "elfutils", "0.173-1.fc28", rpm.ParserName},
|
||||
{"dbus", "1:1.12.10-1.fc28", "dbus", "1.12.10-1.fc28", rpm.ParserName},
|
||||
{"libnghttp2", "1.32.1-1.fc28", "nghttp2", "1.32.1-1.fc28", rpm.ParserName},
|
||||
{"librepo", "1.8.1-7.fc28", "librepo", "1.8.1-7.fc28", rpm.ParserName},
|
||||
{"curl", "7.59.0-6.fc28", "curl", "7.59.0-6.fc28", rpm.ParserName},
|
||||
{"rpm-libs", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"libsolv", "0.6.35-1.fc28", "libsolv", "0.6.35-1.fc28", rpm.ParserName},
|
||||
{"python3-hawkey", "0.11.1-3.fc28", "libdnf", "0.11.1-3.fc28", rpm.ParserName},
|
||||
{"rpm-sign-libs", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"python3-dnf", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName},
|
||||
{"dnf-yum", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName},
|
||||
{"rpm-plugin-systemd-inhibit", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName},
|
||||
{"nss-tools", "3.38.0-1.0.fc28", "nss", "3.38.0-1.0.fc28", rpm.ParserName},
|
||||
{"openssl-pkcs11", "0.4.8-1.fc28", "openssl-pkcs11", "0.4.8-1.fc28", rpm.ParserName},
|
||||
{"vim-minimal", "2:8.1.328-1.fc28", "vim", "8.1.328-1.fc28", rpm.ParserName},
|
||||
{"glibc-langpack-en", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName},
|
||||
{"rootfiles", "8.1-22.fc28", "rootfiles", "8.1-22.fc28", rpm.ParserName},
|
||||
{"libmount", "2.32.1-1.fc28", "rpm", "binary"},
|
||||
{"libffi", "3.1-16.fc28", "rpm", "binary"},
|
||||
{"libunistring", "0.9.10-1.fc28", "rpm", "binary"},
|
||||
{"fedora-repos", "28-5", "rpm", "binary"},
|
||||
{"libarchive", "3.3.1-4.fc28", "rpm", "source"},
|
||||
{"langpacks", "1.0-12.fc28", "rpm", "source"},
|
||||
{"readline", "7.0-11.fc28", "rpm", "source"},
|
||||
{"gzip", "1.9-3.fc28", "rpm", "source"},
|
||||
{"libverto", "0.3.0-5.fc28", "rpm", "source"},
|
||||
{"ncurses-base", "6.1-5.20180224.fc28", "rpm", "binary"},
|
||||
{"libfdisk", "2.32.1-1.fc28", "rpm", "binary"},
|
||||
{"libselinux", "2.8-1.fc28", "rpm", "source"},
|
||||
{"nss-util", "3.38.0-1.0.fc28", "rpm", "source"},
|
||||
{"mpfr", "3.1.6-1.fc28", "rpm", "source"},
|
||||
{"libunistring", "0.9.10-1.fc28", "rpm", "source"},
|
||||
{"libpcap", "14:1.9.0-1.fc28", "rpm", "binary"},
|
||||
{"libarchive", "3.3.1-4.fc28", "rpm", "binary"},
|
||||
{"gmp", "1:6.1.2-7.fc28", "rpm", "binary"},
|
||||
{"crypto-policies", "20180425-5.git6ad4018.fc28", "rpm", "source"},
|
||||
{"gzip", "1.9-3.fc28", "rpm", "binary"},
|
||||
{"fedora-release", "28-2", "rpm", "source"},
|
||||
{"zlib", "1.2.11-8.fc28", "rpm", "binary"},
|
||||
{"crypto-policies", "20180425-5.git6ad4018.fc28", "rpm", "binary"},
|
||||
{"lz4", "1.8.1.2-4.fc28", "rpm", "source"},
|
||||
{"keyutils", "1.5.10-6.fc28", "rpm", "source"},
|
||||
{"gpgme", "1.10.0-4.fc28", "rpm", "binary"},
|
||||
{"libgpg-error", "1.31-1.fc28", "rpm", "binary"},
|
||||
{"gnutls", "3.6.3-4.fc28", "rpm", "source"},
|
||||
{"coreutils", "8.29-7.fc28", "rpm", "source"},
|
||||
{"libsepol", "2.8-1.fc28", "rpm", "source"},
|
||||
{"libssh", "0.8.2-1.fc28", "rpm", "binary"},
|
||||
{"libpwquality", "1.4.0-7.fc28", "rpm", "binary"},
|
||||
{"dnf-conf", "2.7.5-12.fc28", "rpm", "binary"},
|
||||
{"basesystem", "11-5.fc28", "rpm", "source"},
|
||||
{"setup", "2.11.4-1.fc28", "rpm", "binary"},
|
||||
{"libmetalink", "0.1.3-6.fc28", "rpm", "source"},
|
||||
{"texinfo", "6.5-4.fc28", "rpm", "source"},
|
||||
{"expat", "2.2.5-3.fc28", "rpm", "source"},
|
||||
{"ncurses", "6.1-5.20180224.fc28", "rpm", "source"},
|
||||
{"libpwquality", "1.4.0-7.fc28", "rpm", "source"},
|
||||
{"pcre", "8.42-3.fc28", "rpm", "binary"},
|
||||
{"sssd", "1.16.3-2.fc28", "rpm", "source"},
|
||||
{"basesystem", "11-5.fc28", "rpm", "binary"},
|
||||
{"systemd-pam", "238-9.git0e0aa59.fc28", "rpm", "binary"},
|
||||
{"python3-six", "1.11.0-3.fc28", "rpm", "binary"},
|
||||
{"libcurl", "7.59.0-6.fc28", "rpm", "binary"},
|
||||
{"qrencode", "3.4.4-5.fc28", "rpm", "source"},
|
||||
{"xz", "5.2.4-2.fc28", "rpm", "source"},
|
||||
{"libpkgconf", "1.4.2-1.fc28", "rpm", "binary"},
|
||||
{"libzstd", "1.3.5-1.fc28", "rpm", "binary"},
|
||||
{"bash", "4.4.23-1.fc28", "rpm", "binary"},
|
||||
{"cyrus-sasl", "2.1.27-0.2rc7.fc28", "rpm", "source"},
|
||||
{"ncurses-libs", "6.1-5.20180224.fc28", "rpm", "binary"},
|
||||
{"xz-libs", "5.2.4-2.fc28", "rpm", "binary"},
|
||||
{"dbus", "1.12.10-1.fc28", "rpm", "source"},
|
||||
{"grep", "3.1-5.fc28", "rpm", "binary"},
|
||||
{"libusbx", "1.0.22-1.fc28", "rpm", "binary"},
|
||||
{"audit", "2.8.4-2.fc28", "rpm", "source"},
|
||||
{"sed", "4.5-1.fc28", "rpm", "binary"},
|
||||
{"sqlite", "3.22.0-4.fc28", "rpm", "source"},
|
||||
{"openldap", "2.4.46-3.fc28", "rpm", "binary"},
|
||||
{"gawk", "4.2.1-1.fc28", "rpm", "binary"},
|
||||
{"gpgme", "1.10.0-4.fc28", "rpm", "source"},
|
||||
{"lvm2", "2.02.177-5.fc28", "rpm", "source"},
|
||||
{"nspr", "4.19.0-1.fc28", "rpm", "source"},
|
||||
{"libsolv", "0.6.35-1.fc28", "rpm", "source"},
|
||||
{"info", "6.5-4.fc28", "rpm", "binary"},
|
||||
{"openssl-libs", "1:1.1.0h-3.fc28", "rpm", "binary"},
|
||||
{"libxcrypt", "4.1.2-1.fc28", "rpm", "binary"},
|
||||
{"libselinux", "2.8-1.fc28", "rpm", "binary"},
|
||||
{"libgcc", "8.1.1-5.fc28", "rpm", "binary"},
|
||||
{"cracklib", "2.9.6-13.fc28", "rpm", "binary"},
|
||||
{"python3-libs", "3.6.6-1.fc28", "rpm", "binary"},
|
||||
{"glibc-langpack-en", "2.27-32.fc28", "rpm", "binary"},
|
||||
{"json-c", "0.13.1-2.fc28", "rpm", "binary"},
|
||||
{"gnupg2", "2.2.8-1.fc28", "rpm", "source"},
|
||||
{"openssl", "1:1.1.0h-3.fc28", "rpm", "binary"},
|
||||
{"glibc-common", "2.27-32.fc28", "rpm", "binary"},
|
||||
{"p11-kit-trust", "0.23.12-1.fc28", "rpm", "binary"},
|
||||
{"zstd", "1.3.5-1.fc28", "rpm", "source"},
|
||||
{"libxml2", "2.9.8-4.fc28", "rpm", "source"},
|
||||
{"dbus", "1:1.12.10-1.fc28", "rpm", "binary"},
|
||||
{"ca-certificates", "2018.2.24-1.0.fc28", "rpm", "binary"},
|
||||
{"libcomps", "0.1.8-11.fc28", "rpm", "binary"},
|
||||
{"nss", "3.38.0-1.0.fc28", "rpm", "binary"},
|
||||
{"libcom_err", "1.44.2-0.fc28", "rpm", "binary"},
|
||||
{"keyutils-libs", "1.5.10-6.fc28", "rpm", "binary"},
|
||||
{"libseccomp", "2.3.3-2.fc28", "rpm", "binary"},
|
||||
{"elfutils-libs", "0.173-1.fc28", "rpm", "binary"},
|
||||
{"libuuid", "2.32.1-1.fc28", "rpm", "binary"},
|
||||
{"pkgconf", "1.4.2-1.fc28", "rpm", "source"},
|
||||
{"grep", "3.1-5.fc28", "rpm", "source"},
|
||||
{"libpcap", "1.9.0-1.fc28", "rpm", "source"},
|
||||
{"deltarpm", "3.6-25.fc28", "rpm", "binary"},
|
||||
{"krb5-libs", "1.16.1-13.fc28", "rpm", "binary"},
|
||||
{"glibc", "2.27-32.fc28", "rpm", "binary"},
|
||||
{"libseccomp", "2.3.3-2.fc28", "rpm", "source"},
|
||||
{"libsemanage", "2.8-2.fc28", "rpm", "binary"},
|
||||
{"openssl-pkcs11", "0.4.8-1.fc28", "rpm", "binary"},
|
||||
{"libxml2", "2.9.8-4.fc28", "rpm", "binary"},
|
||||
{"e2fsprogs", "1.44.2-0.fc28", "rpm", "source"},
|
||||
{"file-libs", "5.33-7.fc28", "rpm", "binary"},
|
||||
{"elfutils-default-yama-scope", "0.173-1.fc28", "rpm", "binary"},
|
||||
{"glibc", "2.27-32.fc28", "rpm", "source"},
|
||||
{"publicsuffix-list-dafsa", "20180514-1.fc28", "rpm", "binary"},
|
||||
{"popt", "1.16-14.fc28", "rpm", "binary"},
|
||||
{"libnsl2", "1.2.0-2.20180605git4a062cf.fc28", "rpm", "binary"},
|
||||
{"lua-libs", "5.3.4-10.fc28", "rpm", "binary"},
|
||||
{"libsemanage", "2.8-2.fc28", "rpm", "source"},
|
||||
{"glibc-minimal-langpack", "2.27-32.fc28", "rpm", "binary"},
|
||||
{"attr", "2.4.48-3.fc28", "rpm", "source"},
|
||||
{"gdbm", "1.14.1-4.fc28", "rpm", "source"},
|
||||
{"pkgconf", "1.4.2-1.fc28", "rpm", "binary"},
|
||||
{"acl", "2.2.53-1.fc28", "rpm", "source"},
|
||||
{"gnutls", "3.6.3-4.fc28", "rpm", "binary"},
|
||||
{"fedora-repos", "28-5", "rpm", "source"},
|
||||
{"python3-pip", "9.0.3-2.fc28", "rpm", "binary"},
|
||||
{"libnsl2", "1.2.0-2.20180605git4a062cf.fc28", "rpm", "source"},
|
||||
{"rpm", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"libutempter", "1.1.6-14.fc28", "rpm", "source"},
|
||||
{"libdnf", "0.11.1-3.fc28", "rpm", "source"},
|
||||
{"vim-minimal", "2:8.1.328-1.fc28", "rpm", "binary"},
|
||||
{"tzdata", "2018e-1.fc28", "rpm", "binary"},
|
||||
{"nettle", "3.4-2.fc28", "rpm", "binary"},
|
||||
{"python-pip", "9.0.3-2.fc28", "rpm", "source"},
|
||||
{"python-six", "1.11.0-3.fc28", "rpm", "source"},
|
||||
{"diffutils", "3.6-4.fc28", "rpm", "binary"},
|
||||
{"rpm-plugin-selinux", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"shadow-utils", "2:4.6-1.fc28", "rpm", "binary"},
|
||||
{"pkgconf-pkg-config", "1.4.2-1.fc28", "rpm", "binary"},
|
||||
{"cracklib-dicts", "2.9.6-13.fc28", "rpm", "binary"},
|
||||
{"libblkid", "2.32.1-1.fc28", "rpm", "binary"},
|
||||
{"python-setuptools", "39.2.0-6.fc28", "rpm", "source"},
|
||||
{"libsss_idmap", "1.16.3-2.fc28", "rpm", "binary"},
|
||||
{"libksba", "1.3.5-7.fc28", "rpm", "source"},
|
||||
{"sssd-client", "1.16.3-2.fc28", "rpm", "binary"},
|
||||
{"curl", "7.59.0-6.fc28", "rpm", "binary"},
|
||||
{"pam", "1.3.1-1.fc28", "rpm", "binary"},
|
||||
{"libsigsegv", "2.11-5.fc28", "rpm", "binary"},
|
||||
{"langpacks-en", "1.0-12.fc28", "rpm", "binary"},
|
||||
{"nss-softokn-freebl", "3.38.0-1.0.fc28", "rpm", "binary"},
|
||||
{"glib2", "2.56.1-4.fc28", "rpm", "binary"},
|
||||
{"python3-gobject-base", "3.28.3-1.fc28", "rpm", "binary"},
|
||||
{"libffi", "3.1-16.fc28", "rpm", "source"},
|
||||
{"libmodulemd", "1.6.2-2.fc28", "rpm", "source"},
|
||||
{"openssl", "1.1.0h-3.fc28", "rpm", "source"},
|
||||
{"libyaml", "0.1.7-5.fc28", "rpm", "source"},
|
||||
{"pam", "1.3.1-1.fc28", "rpm", "source"},
|
||||
{"iptables", "1.6.2-3.fc28", "rpm", "source"},
|
||||
{"util-linux", "2.32.1-1.fc28", "rpm", "source"},
|
||||
{"libsmartcols", "2.32.1-1.fc28", "rpm", "binary"},
|
||||
{"dnf", "2.7.5-12.fc28", "rpm", "binary"},
|
||||
{"glib2", "2.56.1-4.fc28", "rpm", "source"},
|
||||
{"lua", "5.3.4-10.fc28", "rpm", "source"},
|
||||
{"nss-softokn", "3.38.0-1.0.fc28", "rpm", "source"},
|
||||
{"python3-dnf", "2.7.5-12.fc28", "rpm", "binary"},
|
||||
{"filesystem", "3.8-2.fc28", "rpm", "binary"},
|
||||
{"libsss_nss_idmap", "1.16.3-2.fc28", "rpm", "binary"},
|
||||
{"pcre2", "10.31-10.fc28", "rpm", "source"},
|
||||
{"libyaml", "0.1.7-5.fc28", "rpm", "binary"},
|
||||
{"python3-rpm", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"zlib", "1.2.11-8.fc28", "rpm", "source"},
|
||||
{"libutempter", "1.1.6-14.fc28", "rpm", "binary"},
|
||||
{"pcre2", "10.31-10.fc28", "rpm", "binary"},
|
||||
{"libtirpc", "1.0.3-3.rc2.fc28", "rpm", "source"},
|
||||
{"pkgconf-m4", "1.4.2-1.fc28", "rpm", "binary"},
|
||||
{"libreport", "2.9.5-1.fc28", "rpm", "source"},
|
||||
{"vim", "8.1.328-1.fc28", "rpm", "source"},
|
||||
{"file", "5.33-7.fc28", "rpm", "source"},
|
||||
{"shadow-utils", "4.6-1.fc28", "rpm", "source"},
|
||||
{"sqlite-libs", "3.22.0-4.fc28", "rpm", "binary"},
|
||||
{"setup", "2.11.4-1.fc28", "rpm", "source"},
|
||||
{"gcc", "8.1.1-5.fc28", "rpm", "source"},
|
||||
{"mpfr", "3.1.6-1.fc28", "rpm", "binary"},
|
||||
{"device-mapper", "1.02.146-5.fc28", "rpm", "binary"},
|
||||
{"p11-kit", "0.23.12-1.fc28", "rpm", "source"},
|
||||
{"fedora-release", "28-2", "rpm", "binary"},
|
||||
{"libnghttp2", "1.32.1-1.fc28", "rpm", "binary"},
|
||||
{"libcap-ng", "0.7.9-4.fc28", "rpm", "source"},
|
||||
{"iptables-libs", "1.6.2-3.fc28", "rpm", "binary"},
|
||||
{"audit-libs", "2.8.4-2.fc28", "rpm", "binary"},
|
||||
{"libsigsegv", "2.11-5.fc28", "rpm", "source"},
|
||||
{"rootfiles", "8.1-22.fc28", "rpm", "source"},
|
||||
{"kmod-libs", "25-2.fc28", "rpm", "binary"},
|
||||
{"lz4-libs", "1.8.1.2-4.fc28", "rpm", "binary"},
|
||||
{"libassuan", "2.5.1-3.fc28", "rpm", "source"},
|
||||
{"p11-kit", "0.23.12-1.fc28", "rpm", "binary"},
|
||||
{"nss-sysinit", "3.38.0-1.0.fc28", "rpm", "binary"},
|
||||
{"libcap-ng", "0.7.9-4.fc28", "rpm", "binary"},
|
||||
{"bash", "4.4.23-1.fc28", "rpm", "source"},
|
||||
{"pygobject3", "3.28.3-1.fc28", "rpm", "source"},
|
||||
{"dnf-yum", "2.7.5-12.fc28", "rpm", "binary"},
|
||||
{"nss-softokn", "3.38.0-1.0.fc28", "rpm", "binary"},
|
||||
{"expat", "2.2.5-3.fc28", "rpm", "binary"},
|
||||
{"libassuan", "2.5.1-3.fc28", "rpm", "binary"},
|
||||
{"libdb", "5.3.28-30.fc28", "rpm", "binary"},
|
||||
{"tar", "2:1.30-3.fc28", "rpm", "binary"},
|
||||
{"sed", "4.5-1.fc28", "rpm", "source"},
|
||||
{"libmetalink", "0.1.3-6.fc28", "rpm", "binary"},
|
||||
{"python-smartcols", "0.3.0-2.fc28", "rpm", "source"},
|
||||
{"systemd", "238-9.git0e0aa59.fc28", "rpm", "source"},
|
||||
{"python-iniparse", "0.4-30.fc28", "rpm", "source"},
|
||||
{"libsepol", "2.8-1.fc28", "rpm", "binary"},
|
||||
{"libattr", "2.4.48-3.fc28", "rpm", "binary"},
|
||||
{"python3-smartcols", "0.3.0-2.fc28", "rpm", "binary"},
|
||||
{"libdb", "5.3.28-30.fc28", "rpm", "source"},
|
||||
{"libmodulemd", "1.6.2-2.fc28", "rpm", "binary"},
|
||||
{"python3-hawkey", "0.11.1-3.fc28", "rpm", "binary"},
|
||||
{"dbus-libs", "1:1.12.10-1.fc28", "rpm", "binary"},
|
||||
{"chkconfig", "1.10-4.fc28", "rpm", "source"},
|
||||
{"libargon2", "20161029-5.fc28", "rpm", "binary"},
|
||||
{"openssl-pkcs11", "0.4.8-1.fc28", "rpm", "source"},
|
||||
{"libusbx", "1.0.22-1.fc28", "rpm", "source"},
|
||||
{"python3-setuptools", "39.2.0-6.fc28", "rpm", "binary"},
|
||||
{"chkconfig", "1.10-4.fc28", "rpm", "binary"},
|
||||
{"openldap", "2.4.46-3.fc28", "rpm", "source"},
|
||||
{"bzip2", "1.0.6-26.fc28", "rpm", "source"},
|
||||
{"npth", "1.5-4.fc28", "rpm", "source"},
|
||||
{"libtirpc", "1.0.3-3.rc2.fc28", "rpm", "binary"},
|
||||
{"util-linux", "2.32.1-1.fc28", "rpm", "binary"},
|
||||
{"nss", "3.38.0-1.0.fc28", "rpm", "source"},
|
||||
{"elfutils", "0.173-1.fc28", "rpm", "source"},
|
||||
{"libcomps", "0.1.8-11.fc28", "rpm", "source"},
|
||||
{"libxcrypt", "4.1.2-1.fc28", "rpm", "source"},
|
||||
{"gnupg2", "2.2.8-1.fc28", "rpm", "binary"},
|
||||
{"libdnf", "0.11.1-3.fc28", "rpm", "binary"},
|
||||
{"cracklib", "2.9.6-13.fc28", "rpm", "source"},
|
||||
{"libidn2", "2.0.5-1.fc28", "rpm", "source"},
|
||||
{"bzip2-libs", "1.0.6-26.fc28", "rpm", "binary"},
|
||||
{"json-c", "0.13.1-2.fc28", "rpm", "source"},
|
||||
{"gdbm", "1:1.14.1-4.fc28", "rpm", "binary"},
|
||||
{"pcre", "8.42-3.fc28", "rpm", "source"},
|
||||
{"systemd", "238-9.git0e0aa59.fc28", "rpm", "binary"},
|
||||
{"cryptsetup-libs", "2.0.4-1.fc28", "rpm", "binary"},
|
||||
{"dnf", "2.7.5-12.fc28", "rpm", "source"},
|
||||
{"ca-certificates", "2018.2.24-1.0.fc28", "rpm", "source"},
|
||||
{"libidn2", "2.0.5-1.fc28", "rpm", "binary"},
|
||||
{"libpsl", "0.20.2-2.fc28", "rpm", "binary"},
|
||||
{"gdbm-libs", "1:1.14.1-4.fc28", "rpm", "binary"},
|
||||
{"kmod", "25-2.fc28", "rpm", "source"},
|
||||
{"libreport-filesystem", "2.9.5-1.fc28", "rpm", "binary"},
|
||||
{"ima-evm-utils", "1.1-2.fc28", "rpm", "source"},
|
||||
{"nghttp2", "1.32.1-1.fc28", "rpm", "source"},
|
||||
{"cyrus-sasl-lib", "2.1.27-0.2rc7.fc28", "rpm", "binary"},
|
||||
{"libsolv", "0.6.35-1.fc28", "rpm", "binary"},
|
||||
{"cryptsetup", "2.0.4-1.fc28", "rpm", "source"},
|
||||
{"filesystem", "3.8-2.fc28", "rpm", "source"},
|
||||
{"libcap", "2.25-9.fc28", "rpm", "source"},
|
||||
{"libpsl", "0.20.2-2.fc28", "rpm", "source"},
|
||||
{"deltarpm", "3.6-25.fc28", "rpm", "source"},
|
||||
{"fedora-gpg-keys", "28-5", "rpm", "binary"},
|
||||
{"ima-evm-utils", "1.1-2.fc28", "rpm", "binary"},
|
||||
{"nss-tools", "3.38.0-1.0.fc28", "rpm", "binary"},
|
||||
{"libtasn1", "4.13-2.fc28", "rpm", "source"},
|
||||
{"elfutils-libelf", "0.173-1.fc28", "rpm", "binary"},
|
||||
{"device-mapper-libs", "1.02.146-5.fc28", "rpm", "binary"},
|
||||
{"gobject-introspection", "1.56.1-1.fc28", "rpm", "source"},
|
||||
{"publicsuffix-list", "20180514-1.fc28", "rpm", "source"},
|
||||
{"libcap", "2.25-9.fc28", "rpm", "binary"},
|
||||
{"librepo", "1.8.1-7.fc28", "rpm", "binary"},
|
||||
{"rpm-sign-libs", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"coreutils-single", "8.29-7.fc28", "rpm", "binary"},
|
||||
{"libacl", "2.2.53-1.fc28", "rpm", "binary"},
|
||||
{"popt", "1.16-14.fc28", "rpm", "source"},
|
||||
{"libtasn1", "4.13-2.fc28", "rpm", "binary"},
|
||||
{"gawk", "4.2.1-1.fc28", "rpm", "source"},
|
||||
{"diffutils", "3.6-4.fc28", "rpm", "source"},
|
||||
{"libgpg-error", "1.31-1.fc28", "rpm", "source"},
|
||||
{"libdb-utils", "5.3.28-30.fc28", "rpm", "binary"},
|
||||
{"python3-iniparse", "0.4-30.fc28", "rpm", "binary"},
|
||||
{"acl", "2.2.53-1.fc28", "rpm", "binary"},
|
||||
{"libssh", "0.8.2-1.fc28", "rpm", "source"},
|
||||
{"python3-librepo", "1.8.1-7.fc28", "rpm", "binary"},
|
||||
{"gobject-introspection", "1.56.1-1.fc28", "rpm", "binary"},
|
||||
{"rpm", "4.14.1-9.fc28", "rpm", "source"},
|
||||
{"libgcrypt", "1.8.3-1.fc28", "rpm", "source"},
|
||||
{"curl", "7.59.0-6.fc28", "rpm", "source"},
|
||||
{"tzdata", "2018e-1.fc28", "rpm", "source"},
|
||||
{"krb5", "1.16.1-13.fc28", "rpm", "source"},
|
||||
{"librepo", "1.8.1-7.fc28", "rpm", "source"},
|
||||
{"python3-gpg", "1.10.0-4.fc28", "rpm", "binary"},
|
||||
{"nettle", "3.4-2.fc28", "rpm", "source"},
|
||||
{"libgcrypt", "1.8.3-1.fc28", "rpm", "binary"},
|
||||
{"python3", "3.6.6-1.fc28", "rpm", "binary"},
|
||||
{"python3-libcomps", "0.1.8-11.fc28", "rpm", "binary"},
|
||||
{"rpm-libs", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"nspr", "4.19.0-1.fc28", "rpm", "binary"},
|
||||
{"argon2", "20161029-5.fc28", "rpm", "source"},
|
||||
{"tar", "1.30-3.fc28", "rpm", "source"},
|
||||
{"qrencode-libs", "3.4.4-5.fc28", "rpm", "binary"},
|
||||
{"gmp", "6.1.2-7.fc28", "rpm", "source"},
|
||||
{"libverto", "0.3.0-5.fc28", "rpm", "binary"},
|
||||
{"python3", "3.6.6-1.fc28", "rpm", "source"},
|
||||
{"libksba", "1.3.5-7.fc28", "rpm", "binary"},
|
||||
{"readline", "7.0-11.fc28", "rpm", "binary"},
|
||||
{"rpm-build-libs", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"npth", "1.5-4.fc28", "rpm", "binary"},
|
||||
{"rootfiles", "8.1-22.fc28", "rpm", "binary"},
|
||||
{"rpm-plugin-systemd-inhibit", "4.14.1-9.fc28", "rpm", "binary"},
|
||||
{"systemd-libs", "238-9.git0e0aa59.fc28", "rpm", "binary"},
|
||||
{"nss-util", "3.38.0-1.0.fc28", "rpm", "binary"},
|
||||
}
|
||||
|
||||
func TestRpmFeatureDetection(t *testing.T) {
|
||||
@ -206,8 +334,10 @@ func TestRpmFeatureDetection(t *testing.T) {
|
||||
"valid small case",
|
||||
map[string]string{"var/lib/rpm/Packages": "rpm/testdata/valid"},
|
||||
[]database.Feature{
|
||||
{"centos-release", "7-1.1503.el7.centos.2.8", "centos-release", "7-1.1503.el7.centos.2.8", rpm.ParserName},
|
||||
{"filesystem", "3.2-18.el7", "filesystem", "3.2-18.el7", rpm.ParserName},
|
||||
{"centos-release", "7-1.1503.el7.centos.2.8", "rpm", "binary"},
|
||||
{"filesystem", "3.2-18.el7", "rpm", "binary"},
|
||||
{"centos-release", "7-1.1503.el7.centos.2.8", "rpm", "source"},
|
||||
{"filesystem", "3.2-18.el7", "rpm", "source"},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -248,15 +378,14 @@ func TestParseSourceRPM(t *testing.T) {
|
||||
// actual expected: name="lua", version="5.3.4", release="10.fc-28"
|
||||
{"lua-5.3.4-10.fc-28.src.rpm", "lua-5.3.4", "10.fc-28", ""},
|
||||
} {
|
||||
pkg := database.Feature{}
|
||||
err := parseSourceRPM(test.sourceRPM, &pkg)
|
||||
name, version, release, _, err := parseSourceRPM(test.sourceRPM)
|
||||
if test.expectedErr != "" {
|
||||
require.EqualError(t, err, test.expectedErr)
|
||||
continue
|
||||
}
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, test.expectedName, pkg.SourceName)
|
||||
require.Equal(t, test.expectedVersion, pkg.SourceVersion)
|
||||
require.Equal(t, test.expectedName, name)
|
||||
require.Equal(t, test.expectedVersion, version+"-"+release)
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ const (
|
||||
nvdURLPrefix = "https://cve.mitre.org/cgi-bin/cvename.cgi?name="
|
||||
// affected type indicates if the affected feature hint is for binary or
|
||||
// source package.
|
||||
affectedType = database.AffectBinaryPackage
|
||||
affectedType = database.BinaryPackage
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -177,7 +177,7 @@ func (file *secDB) Vulnerabilities() (vulns []database.VulnerabilityWithAffected
|
||||
|
||||
vuln.Affected = []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
FeatureName: pkg.Pkg.Name,
|
||||
AffectedVersion: version,
|
||||
FixedInVersion: fixedInVersion,
|
||||
|
@ -38,7 +38,7 @@ const (
|
||||
url = "https://security-tracker.debian.org/tracker/data/json"
|
||||
cveURLPrefix = "https://security-tracker.debian.org/tracker"
|
||||
updaterFlag = "debianUpdater"
|
||||
affectedType = database.AffectSourcePackage
|
||||
affectedType = database.SourcePackage
|
||||
)
|
||||
|
||||
type jsonData map[string]map[string]jsonVuln
|
||||
@ -215,7 +215,7 @@ func parseDebianJSON(data *jsonData) (vulnerabilities []database.VulnerabilityWi
|
||||
|
||||
// Create and add the feature version.
|
||||
pkg := database.AffectedFeature{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
FeatureName: pkgName,
|
||||
AffectedVersion: version,
|
||||
FixedInVersion: fixedInVersion,
|
||||
|
@ -41,7 +41,7 @@ func TestDebianParser(t *testing.T) {
|
||||
|
||||
expectedFeatures := []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian:8",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
@ -50,7 +50,7 @@ func TestDebianParser(t *testing.T) {
|
||||
AffectedVersion: versionfmt.MaxVersion,
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian:unstable",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
@ -71,7 +71,7 @@ func TestDebianParser(t *testing.T) {
|
||||
|
||||
expectedFeatures := []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian:8",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
@ -81,7 +81,7 @@ func TestDebianParser(t *testing.T) {
|
||||
AffectedVersion: "0.7.0",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian:unstable",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
@ -91,7 +91,7 @@ func TestDebianParser(t *testing.T) {
|
||||
AffectedVersion: "0.7.0",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian:8",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
|
@ -41,7 +41,7 @@ const (
|
||||
ovalURI = "https://linux.oracle.com/oval/"
|
||||
elsaFilePrefix = "com.oracle.elsa-"
|
||||
updaterFlag = "oracleUpdater"
|
||||
affectedType = database.AffectBinaryPackage
|
||||
affectedType = database.BinaryPackage
|
||||
)
|
||||
|
||||
var (
|
||||
@ -365,7 +365,7 @@ func toFeatures(criteria criteria) []database.AffectedFeature {
|
||||
} else if strings.Contains(c.Comment, " is earlier than ") {
|
||||
const prefixLen = len(" is earlier than ")
|
||||
featureVersion.FeatureName = strings.TrimSpace(c.Comment[:strings.Index(c.Comment, " is earlier than ")])
|
||||
featureVersion.AffectedType = affectedType
|
||||
featureVersion.FeatureType = affectedType
|
||||
version := c.Comment[strings.Index(c.Comment, " is earlier than ")+prefixLen:]
|
||||
err := versionfmt.Valid(rpm.ParserName, version)
|
||||
if err != nil {
|
||||
|
@ -43,7 +43,7 @@ func TestOracleParserOneCve(t *testing.T) {
|
||||
|
||||
expectedFeatures := []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "oracle:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
@ -53,7 +53,7 @@ func TestOracleParserOneCve(t *testing.T) {
|
||||
AffectedVersion: "0:3.1.1-7.el7_1",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "oracle:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
@ -63,7 +63,7 @@ func TestOracleParserOneCve(t *testing.T) {
|
||||
AffectedVersion: "0:3.1.1-7.el7_1",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "oracle:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
|
@ -43,7 +43,7 @@ const (
|
||||
ovalURI = "https://www.redhat.com/security/data/oval/"
|
||||
rhsaFilePrefix = "com.redhat.rhsa-"
|
||||
updaterFlag = "rhelUpdater"
|
||||
affectedType = database.AffectBinaryPackage
|
||||
affectedType = database.BinaryPackage
|
||||
)
|
||||
|
||||
var (
|
||||
@ -333,7 +333,7 @@ func toFeatures(criteria criteria) []database.AffectedFeature {
|
||||
} else if strings.Contains(c.Comment, " is earlier than ") {
|
||||
const prefixLen = len(" is earlier than ")
|
||||
featureVersion.FeatureName = strings.TrimSpace(c.Comment[:strings.Index(c.Comment, " is earlier than ")])
|
||||
featureVersion.AffectedType = affectedType
|
||||
featureVersion.FeatureType = affectedType
|
||||
version := c.Comment[strings.Index(c.Comment, " is earlier than ")+prefixLen:]
|
||||
err := versionfmt.Valid(rpm.ParserName, version)
|
||||
if err != nil {
|
||||
|
@ -46,7 +46,7 @@ func TestRHELParserMultipleCVE(t *testing.T) {
|
||||
database.MediumSeverity, database.MediumSeverity}
|
||||
expectedFeatures := []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "centos:6",
|
||||
VersionFormat: rpm.ParserName,
|
||||
@ -56,7 +56,7 @@ func TestRHELParserMultipleCVE(t *testing.T) {
|
||||
AffectedVersion: "0:38.1.0-1.el6_6",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "centos:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
@ -96,7 +96,7 @@ func TestRHELParserOneCVE(t *testing.T) {
|
||||
|
||||
expectedFeatures := []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "centos:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
@ -106,7 +106,7 @@ func TestRHELParserOneCVE(t *testing.T) {
|
||||
FixedInVersion: "0:3.1.1-7.el7_1",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "centos:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
@ -116,7 +116,7 @@ func TestRHELParserOneCVE(t *testing.T) {
|
||||
FixedInVersion: "0:3.1.1-7.el7_1",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "centos:7",
|
||||
VersionFormat: rpm.ParserName,
|
||||
|
@ -39,7 +39,7 @@ const (
|
||||
trackerURI = "https://git.launchpad.net/ubuntu-cve-tracker"
|
||||
updaterFlag = "ubuntuUpdater"
|
||||
cveURL = "http://people.ubuntu.com/~ubuntu-security/cve/%s"
|
||||
affectedType = database.AffectSourcePackage
|
||||
affectedType = database.SourcePackage
|
||||
)
|
||||
|
||||
var (
|
||||
@ -335,7 +335,7 @@ func parseUbuntuCVE(fileContent io.Reader) (vulnerability database.Vulnerability
|
||||
|
||||
// Create and add the new package.
|
||||
featureVersion := database.AffectedFeature{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: releaseName,
|
||||
VersionFormat: dpkg.ParserName,
|
||||
|
@ -46,7 +46,7 @@ func TestUbuntuParser(t *testing.T) {
|
||||
|
||||
expectedFeatures := []database.AffectedFeature{
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "ubuntu:14.04",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
@ -55,7 +55,7 @@ func TestUbuntuParser(t *testing.T) {
|
||||
AffectedVersion: versionfmt.MaxVersion,
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "ubuntu:15.04",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
@ -65,7 +65,7 @@ func TestUbuntuParser(t *testing.T) {
|
||||
AffectedVersion: "0.4-3",
|
||||
},
|
||||
{
|
||||
AffectedType: affectedType,
|
||||
FeatureType: affectedType,
|
||||
Namespace: database.Namespace{
|
||||
Name: "ubuntu:15.10",
|
||||
VersionFormat: dpkg.ParserName,
|
||||
|
@ -499,7 +499,7 @@ func doVulnerabilitiesNamespacing(vulnerabilities []database.VulnerabilityWithAf
|
||||
|
||||
for _, fv := range namespacedFeatures {
|
||||
// validate vulnerabilities, throw out the invalid vulnerabilities
|
||||
if fv.AffectedType == "" || fv.AffectedVersion == "" || fv.FeatureName == "" || fv.Namespace.Name == "" || fv.Namespace.VersionFormat == "" {
|
||||
if fv.FeatureType == "" || fv.AffectedVersion == "" || fv.FeatureName == "" || fv.Namespace.Name == "" || fv.Namespace.VersionFormat == "" {
|
||||
log.WithFields(log.Fields{
|
||||
"Name": fv.FeatureName,
|
||||
"Affected Version": fv.AffectedVersion,
|
||||
|
@ -183,7 +183,7 @@ func newmockUpdaterDatastore() *mockUpdaterDatastore {
|
||||
|
||||
func TestDoVulnerabilitiesNamespacing(t *testing.T) {
|
||||
fv1 := database.AffectedFeature{
|
||||
AffectedType: database.AffectSourcePackage,
|
||||
FeatureType: database.SourcePackage,
|
||||
Namespace: database.Namespace{Name: "Namespace1"},
|
||||
FeatureName: "Feature1",
|
||||
FixedInVersion: "0.1",
|
||||
@ -191,7 +191,7 @@ func TestDoVulnerabilitiesNamespacing(t *testing.T) {
|
||||
}
|
||||
|
||||
fv2 := database.AffectedFeature{
|
||||
AffectedType: database.AffectSourcePackage,
|
||||
FeatureType: database.SourcePackage,
|
||||
Namespace: database.Namespace{Name: "Namespace2"},
|
||||
FeatureName: "Feature1",
|
||||
FixedInVersion: "0.2",
|
||||
@ -199,7 +199,7 @@ func TestDoVulnerabilitiesNamespacing(t *testing.T) {
|
||||
}
|
||||
|
||||
fv3 := database.AffectedFeature{
|
||||
AffectedType: database.AffectSourcePackage,
|
||||
FeatureType: database.SourcePackage,
|
||||
Namespace: database.Namespace{Name: "Namespace2"},
|
||||
FeatureName: "Feature2",
|
||||
FixedInVersion: "0.3",
|
||||
@ -237,9 +237,9 @@ func TestCreatVulnerabilityNotification(t *testing.T) {
|
||||
VersionFormat: vf1,
|
||||
}
|
||||
af1 := database.AffectedFeature{
|
||||
AffectedType: database.AffectSourcePackage,
|
||||
Namespace: ns1,
|
||||
FeatureName: "feature 1",
|
||||
FeatureType: database.SourcePackage,
|
||||
Namespace: ns1,
|
||||
FeatureName: "feature 1",
|
||||
}
|
||||
|
||||
v1 := database.VulnerabilityWithAffected{
|
||||
|
@ -284,11 +284,15 @@ func TestProcessAncestryWithDistUpgrade(t *testing.T) {
|
||||
{Name: "db", Version: "5.1.29-5"},
|
||||
{Name: "ustr", Version: "1.0.4-3"},
|
||||
{Name: "xz-utils", Version: "5.1.1alpha+20120614-2"},
|
||||
{Name: "libdb5.1", Version: "5.1.29-5"},
|
||||
}
|
||||
|
||||
nonUpgradedMap := map[database.Feature]struct{}{}
|
||||
for _, f := range nonUpgradedFeatures {
|
||||
f.VersionFormat = "dpkg"
|
||||
f.Type = database.SourcePackage
|
||||
nonUpgradedMap[f] = struct{}{}
|
||||
f.Type = database.BinaryPackage
|
||||
nonUpgradedMap[f] = struct{}{}
|
||||
}
|
||||
|
||||
@ -318,12 +322,12 @@ func TestProcessAncestryWithDistUpgrade(t *testing.T) {
|
||||
features = append(features, l.Features...)
|
||||
}
|
||||
|
||||
assert.Len(t, features, 74)
|
||||
assert.Len(t, features, 161)
|
||||
for _, f := range features {
|
||||
if _, ok := nonUpgradedMap[f.Feature]; ok {
|
||||
assert.Equal(t, "debian:7", f.Namespace.Name)
|
||||
assert.Equal(t, "debian:7", f.Namespace.Name, "%#v", f)
|
||||
} else {
|
||||
assert.Equal(t, "debian:8", f.Namespace.Name)
|
||||
assert.Equal(t, "debian:8", f.Namespace.Name, "#%v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -352,8 +356,8 @@ func TestProcessLayers(t *testing.T) {
|
||||
assert.Len(t, LayerWithContents[1].Namespaces, 1)
|
||||
assert.Len(t, LayerWithContents[2].Namespaces, 1)
|
||||
assert.Len(t, LayerWithContents[0].Features, 0)
|
||||
assert.Len(t, LayerWithContents[1].Features, 52)
|
||||
assert.Len(t, LayerWithContents[2].Features, 74)
|
||||
assert.Len(t, LayerWithContents[1].Features, 132)
|
||||
assert.Len(t, LayerWithContents[2].Features, 191)
|
||||
|
||||
// Ensure each layer has expected namespaces and features detected
|
||||
if blank, ok := datastore.layers["blank"]; ok {
|
||||
@ -371,7 +375,7 @@ func TestProcessLayers(t *testing.T) {
|
||||
{database.Namespace{"debian:7", dpkg.ParserName}, database.NewNamespaceDetector("os-release", "1.0")},
|
||||
}, wheezy.Namespaces)
|
||||
|
||||
assert.Len(t, wheezy.Features, 52)
|
||||
assert.Len(t, wheezy.Features, 132)
|
||||
} else {
|
||||
assert.Fail(t, "wheezy is not stored")
|
||||
return
|
||||
@ -382,7 +386,7 @@ func TestProcessLayers(t *testing.T) {
|
||||
assert.Equal(t, []database.LayerNamespace{
|
||||
{database.Namespace{"debian:8", dpkg.ParserName}, database.NewNamespaceDetector("os-release", "1.0")},
|
||||
}, jessie.Namespaces)
|
||||
assert.Len(t, jessie.Features, 74)
|
||||
assert.Len(t, jessie.Features, 191)
|
||||
} else {
|
||||
assert.Fail(t, "jessie is not stored")
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user