Skip to content

Commit 857a076

Browse files
committed
fix(scanner/redhatbase): support for empty release in rpm -qa
1 parent b0c5dec commit 857a076

File tree

2 files changed

+150
-89
lines changed

2 files changed

+150
-89
lines changed

scanner/redhatbase.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ func (o *redhatBase) parseInstalledPackages(stdout string) (models.Packages, mod
523523
case constant.Amazon:
524524
switch strings.Fields(o.getDistro().Release)[0] {
525525
case "2":
526-
switch len(strings.Fields(line)) {
526+
switch len(strings.Split(line, " ")) {
527527
case 6:
528528
binpkg, srcpkg, err = o.parseInstalledPackagesLine(line)
529529
case 7:
@@ -575,7 +575,7 @@ func (o *redhatBase) parseInstalledPackages(stdout string) (models.Packages, mod
575575
}
576576

577577
func (o *redhatBase) parseInstalledPackagesLine(line string) (*models.Package, *models.SrcPackage, error) {
578-
switch fields := strings.Fields(line); len(fields) {
578+
switch fields := strings.Split(line, " "); len(fields) {
579579
case 6, 7:
580580
sp, err := func() (*models.SrcPackage, error) {
581581
switch fields[5] {
@@ -592,8 +592,14 @@ func (o *redhatBase) parseInstalledPackagesLine(line string) (*models.Package, *
592592
Version: func() string {
593593
switch fields[1] {
594594
case "0", "(none)":
595+
if r == "" {
596+
return v
597+
}
595598
return fmt.Sprintf("%s-%s", v, r)
596599
default:
600+
if r == "" {
601+
return fmt.Sprintf("%s:%s", fields[1], v)
602+
}
597603
return fmt.Sprintf("%s:%s-%s", fields[1], v, r)
598604
}
599605
}(),
@@ -631,7 +637,7 @@ func (o *redhatBase) parseInstalledPackagesLine(line string) (*models.Package, *
631637
}
632638

633639
func (o *redhatBase) parseInstalledPackagesLineFromRepoquery(line string) (*models.Package, *models.SrcPackage, error) {
634-
switch fields := strings.Fields(line); len(fields) {
640+
switch fields := strings.Split(line, " "); len(fields) {
635641
case 7:
636642
sp, err := func() (*models.SrcPackage, error) {
637643
switch fields[5] {
@@ -648,8 +654,14 @@ func (o *redhatBase) parseInstalledPackagesLineFromRepoquery(line string) (*mode
648654
Version: func() string {
649655
switch fields[1] {
650656
case "0", "(none)":
657+
if r == "" {
658+
return v
659+
}
651660
return fmt.Sprintf("%s-%s", v, r)
652661
default:
662+
if r == "" {
663+
return fmt.Sprintf("%s:%s", fields[1], v)
664+
}
653665
return fmt.Sprintf("%s:%s-%s", fields[1], v, r)
654666
}
655667
}(),
@@ -699,20 +711,27 @@ func splitFileName(filename string) (name, ver, rel, epoch, arch string, err err
699711
basename := strings.TrimSuffix(filename, ".rpm")
700712

701713
archIndex := strings.LastIndex(basename, ".")
714+
// support not standard style rpm fullname
715+
// e.g.
716+
// baz-0-1-i386 => i386
717+
// qux-0--i386 => i386
718+
if i := strings.LastIndex(basename[archIndex+1:], "-"); i > -1 {
719+
archIndex = archIndex + (i + 1)
720+
}
702721
if archIndex == -1 {
703-
return "", "", "", "", "", xerrors.Errorf("unexpected file name. expected: %q, actual: %q", "<name>-<version>-<release>.<arch>.rpm", fmt.Sprintf("%s.rpm", filename))
722+
return "", "", "", "", "", xerrors.Errorf("unexpected file name. expected: %q, actual: %q", "(<epoch>:)<name>-<version>-(<release>)(.|-)<arch>.rpm", fmt.Sprintf("%s.rpm", filename))
704723
}
705724
arch = basename[archIndex+1:]
706725

707726
relIndex := strings.LastIndex(basename[:archIndex], "-")
708727
if relIndex == -1 {
709-
return "", "", "", "", "", xerrors.Errorf("unexpected file name. expected: %q, actual: %q", "<name>-<version>-<release>.<arch>.rpm", fmt.Sprintf("%s.rpm", filename))
728+
return "", "", "", "", "", xerrors.Errorf("unexpected file name. expected: %q, actual: %q", "(<epoch>:)<name>-<version>-(<release>)(.|-)<arch>.rpm", fmt.Sprintf("%s.rpm", filename))
710729
}
711730
rel = basename[relIndex+1 : archIndex]
712731

713732
verIndex := strings.LastIndex(basename[:relIndex], "-")
714733
if verIndex == -1 {
715-
return "", "", "", "", "", xerrors.Errorf("unexpected file name. expected: %q, actual: %q", "<name>-<version>-<release>.<arch>.rpm", fmt.Sprintf("%s.rpm", filename))
734+
return "", "", "", "", "", xerrors.Errorf("unexpected file name. expected: %q, actual: %q", "(<epoch>:)<name>-<version>-(<release>)(.|-)<arch>.rpm", fmt.Sprintf("%s.rpm", filename))
716735
}
717736
ver = basename[verIndex+1 : relIndex]
718737

@@ -787,7 +806,7 @@ func (o *redhatBase) parseUpdatablePacksLines(stdout string) (models.Packages, e
787806
}
788807

789808
func (o *redhatBase) parseUpdatablePacksLine(line string) (models.Package, error) {
790-
fields := strings.Fields(line)
809+
fields := strings.Split(line, " ")
791810
if len(fields) < 5 {
792811
return models.Package{}, xerrors.Errorf("Unknown format: %s, fields: %s", line, fields)
793812
}

scanner/redhatbase_test.go

Lines changed: 124 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -419,15 +419,52 @@ func Test_redhatBase_parseInstalledPackagesLine(t *testing.T) {
419419
},
420420
},
421421
{
422-
name: "invalid source package",
422+
name: "not standard rpm style source package",
423423
args: args{line: "elasticsearch 0 8.17.0 1 x86_64 elasticsearch-8.17.0-1-src.rpm (none)"},
424424
wantbp: &models.Package{
425425
Name: "elasticsearch",
426426
Version: "8.17.0",
427427
Release: "1",
428428
Arch: "x86_64",
429429
},
430-
wantsp: nil,
430+
wantsp: &models.SrcPackage{
431+
Name: "elasticsearch",
432+
Version: "8.17.0-1",
433+
Arch: "src",
434+
BinaryNames: []string{"elasticsearch"},
435+
},
436+
},
437+
{
438+
name: "not standard rpm style source package 2",
439+
args: args{line: "package 0 0 1 x86_64 package-0-1-src.rpm (none)"},
440+
wantbp: &models.Package{
441+
Name: "package",
442+
Version: "0",
443+
Release: "1",
444+
Arch: "x86_64",
445+
},
446+
wantsp: &models.SrcPackage{
447+
Name: "package",
448+
Version: "0-1",
449+
Arch: "src",
450+
BinaryNames: []string{"package"},
451+
},
452+
},
453+
{
454+
name: "release is empty",
455+
args: args{line: "package 0 0 x86_64 package-0-.src.rpm (none)"},
456+
wantbp: &models.Package{
457+
Name: "package",
458+
Version: "0",
459+
Release: "",
460+
Arch: "x86_64",
461+
},
462+
wantsp: &models.SrcPackage{
463+
Name: "package",
464+
Version: "0",
465+
Arch: "src",
466+
BinaryNames: []string{"package"},
467+
},
431468
},
432469
}
433470
for _, tt := range tests {
@@ -568,140 +605,145 @@ func TestParseYumCheckUpdateLine(t *testing.T) {
568605
}
569606
}
570607

571-
func TestParseYumCheckUpdateLines(t *testing.T) {
572-
r := newCentOS(config.ServerInfo{})
573-
r.Distro = config.Distro{Family: "centos"}
574-
stdout := `audit-libs 0 2.3.7 5.el6 base
608+
func Test_redhatBase_parseUpdatablePacksLines(t *testing.T) {
609+
type fields struct {
610+
base base
611+
sudo rootPriv
612+
}
613+
type args struct {
614+
stdout string
615+
}
616+
tests := []struct {
617+
name string
618+
fields fields
619+
args args
620+
want models.Packages
621+
wantErr bool
622+
}{
623+
{
624+
name: "centos",
625+
fields: fields{
626+
base: base{
627+
Distro: config.Distro{
628+
Family: constant.CentOS,
629+
},
630+
osPackages: osPackages{
631+
Packages: models.Packages{
632+
"audit-libs": {Name: "audit-libs"},
633+
"bash": {Name: "bash"},
634+
"python-libs": {Name: "python-libs"},
635+
"python-ordereddict": {Name: "python-ordereddict"},
636+
"bind-utils": {Name: "bind-utils"},
637+
"pytalloc": {Name: "pytalloc"},
638+
},
639+
},
640+
},
641+
},
642+
args: args{
643+
stdout: `audit-libs 0 2.3.7 5.el6 base
575644
bash 0 4.1.2 33.el6_7.1 updates
576645
python-libs 0 2.6.6 64.el6 rhui-REGION-rhel-server-releases
577646
python-ordereddict 0 1.1 3.el6ev installed
578647
bind-utils 30 9.3.6 25.P1.el5_11.8 updates
579-
pytalloc 0 2.0.7 2.el6 @CentOS 6.5/6.5`
580-
581-
r.Packages = models.NewPackages(
582-
models.Package{Name: "audit-libs"},
583-
models.Package{Name: "bash"},
584-
models.Package{Name: "python-libs"},
585-
models.Package{Name: "python-ordereddict"},
586-
models.Package{Name: "bind-utils"},
587-
models.Package{Name: "pytalloc"},
588-
)
589-
var tests = []struct {
590-
in string
591-
out models.Packages
592-
}{
593-
{
594-
stdout,
595-
models.NewPackages(
596-
models.Package{
648+
pytalloc 0 2.0.7 2.el6 @CentOS 6.5/6.5`,
649+
},
650+
want: models.Packages{
651+
"audit-libs": {
597652
Name: "audit-libs",
598653
NewVersion: "2.3.7",
599654
NewRelease: "5.el6",
600655
Repository: "base",
601656
},
602-
models.Package{
657+
"bash": {
603658
Name: "bash",
604659
NewVersion: "4.1.2",
605660
NewRelease: "33.el6_7.1",
606661
Repository: "updates",
607662
},
608-
models.Package{
663+
"python-libs": {
609664
Name: "python-libs",
610665
NewVersion: "2.6.6",
611666
NewRelease: "64.el6",
612667
Repository: "rhui-REGION-rhel-server-releases",
613668
},
614-
models.Package{
669+
"python-ordereddict": {
615670
Name: "python-ordereddict",
616671
NewVersion: "1.1",
617672
NewRelease: "3.el6ev",
618673
Repository: "installed",
619674
},
620-
models.Package{
675+
"bind-utils": {
621676
Name: "bind-utils",
622677
NewVersion: "30:9.3.6",
623678
NewRelease: "25.P1.el5_11.8",
624679
Repository: "updates",
625680
},
626-
models.Package{
681+
"pytalloc": {
627682
Name: "pytalloc",
628683
NewVersion: "2.0.7",
629684
NewRelease: "2.el6",
630685
Repository: "@CentOS 6.5/6.5",
631686
},
632-
),
687+
},
633688
},
634-
}
635-
636-
for _, tt := range tests {
637-
packages, err := r.parseUpdatablePacksLines(tt.in)
638-
if err != nil {
639-
t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in)
640-
return
641-
}
642-
for name, ePack := range tt.out {
643-
if !reflect.DeepEqual(ePack, packages[name]) {
644-
e := pp.Sprintf("%v", ePack)
645-
a := pp.Sprintf("%v", packages[name])
646-
t.Errorf("expected %s, actual %s", e, a)
647-
}
648-
}
649-
}
650-
}
651-
652-
func TestParseYumCheckUpdateLinesAmazon(t *testing.T) {
653-
r := newAmazon(config.ServerInfo{})
654-
r.Distro = config.Distro{Family: "amazon"}
655-
stdout := `bind-libs 32 9.8.2 0.37.rc1.45.amzn1 amzn-main
656-
java-1.7.0-openjdk 0 1.7.0.95 2.6.4.0.65.amzn1 amzn-main
657-
if-not-architecture 0 100 200 amzn-main`
658-
r.Packages = models.NewPackages(
659-
models.Package{Name: "bind-libs"},
660-
models.Package{Name: "java-1.7.0-openjdk"},
661-
models.Package{Name: "if-not-architecture"},
662-
)
663-
var tests = []struct {
664-
in string
665-
out models.Packages
666-
}{
667689
{
668-
stdout,
669-
models.NewPackages(
670-
models.Package{
690+
name: "amazon",
691+
fields: fields{
692+
base: base{
693+
Distro: config.Distro{
694+
Family: constant.Amazon,
695+
},
696+
osPackages: osPackages{
697+
Packages: models.Packages{
698+
"bind-libs": {Name: "bind-libs"},
699+
"java-1.7.0-openjdk": {Name: "java-1.7.0-openjdk"},
700+
"if-not-architecture": {Name: "if-not-architecture"},
701+
},
702+
},
703+
},
704+
},
705+
args: args{
706+
stdout: `bind-libs 32 9.8.2 0.37.rc1.45.amzn1 amzn-main
707+
java-1.7.0-openjdk 0 1.7.0.95 2.6.4.0.65.amzn1 amzn-main
708+
if-not-architecture 0 100 200 amzn-main`,
709+
},
710+
want: models.Packages{
711+
"bind-libs": {
671712
Name: "bind-libs",
672713
NewVersion: "32:9.8.2",
673714
NewRelease: "0.37.rc1.45.amzn1",
674715
Repository: "amzn-main",
675716
},
676-
models.Package{
717+
"java-1.7.0-openjdk": {
677718
Name: "java-1.7.0-openjdk",
678719
NewVersion: "1.7.0.95",
679720
NewRelease: "2.6.4.0.65.amzn1",
680721
Repository: "amzn-main",
681722
},
682-
models.Package{
723+
"if-not-architecture": {
683724
Name: "if-not-architecture",
684725
NewVersion: "100",
685726
NewRelease: "200",
686727
Repository: "amzn-main",
687728
},
688-
),
729+
},
689730
},
690731
}
691-
692732
for _, tt := range tests {
693-
packages, err := r.parseUpdatablePacksLines(tt.in)
694-
if err != nil {
695-
t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in)
696-
return
697-
}
698-
for name, ePack := range tt.out {
699-
if !reflect.DeepEqual(ePack, packages[name]) {
700-
e := pp.Sprintf("%v", ePack)
701-
a := pp.Sprintf("%v", packages[name])
702-
t.Errorf("[%s] expected %s, actual %s", name, e, a)
733+
t.Run(tt.name, func(t *testing.T) {
734+
o := &redhatBase{
735+
base: tt.fields.base,
736+
sudo: tt.fields.sudo,
703737
}
704-
}
738+
got, err := o.parseUpdatablePacksLines(tt.args.stdout)
739+
if (err != nil) != tt.wantErr {
740+
t.Errorf("redhatBase.parseUpdatablePacksLines() error = %v, wantErr %v", err, tt.wantErr)
741+
return
742+
}
743+
if !reflect.DeepEqual(got, tt.want) {
744+
t.Errorf("redhatBase.parseUpdatablePacksLines() = %v, want %v", got, tt.want)
745+
}
746+
})
705747
}
706748
}
707749

@@ -783,7 +825,7 @@ func Test_redhatBase_parseRpmQfLine(t *testing.T) {
783825
{
784826
name: "valid line",
785827
fields: fields{base: base{}},
786-
args: args{line: "Percona-Server-shared-56 1 5.6.19 rel67.0.el6 x86_64 Percona-SQL-56-5.6.19-rel67.0.el6.src.rpm"},
828+
args: args{line: "Percona-Server-shared-56 1 5.6.19 rel67.0.el6 x86_64 Percona-SQL-56-5.6.19-rel67.0.el6.src.rpm"},
787829
wantPkg: &models.Package{
788830
Name: "Percona-Server-shared-56",
789831
Version: "1:5.6.19",

0 commit comments

Comments
 (0)