feat(scan) detect the dependencies for each updatable packages

This commit is contained in:
Kota Kanbe
2021-11-01 12:45:09 +09:00
parent ffdb78962f
commit 43d987e200
5 changed files with 155 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ import (
"regexp"
"strings"
"github.com/cheggaaa/pb"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
@@ -230,8 +231,7 @@ func (o *redhatBase) preCure() error {
func (o *redhatBase) postScan() error {
if o.isExecYumPS() {
if err := o.pkgPs(o.getOwnerPkgs); err != nil {
err = xerrors.Errorf("Failed to execute yum-ps: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to execute yum-ps: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
}
@@ -239,8 +239,7 @@ func (o *redhatBase) postScan() error {
if o.isExecNeedsRestarting() {
if err := o.needsRestarting(); err != nil {
err = xerrors.Errorf("Failed to execute need-restarting: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to execute need-restarting: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
}
@@ -267,8 +266,7 @@ func (o *redhatBase) scanPackages() (err error) {
fn := func(pkgName string) execResult { return o.exec(fmt.Sprintf("rpm -q --last %s", pkgName), noSudo) }
o.Kernel.RebootRequired, err = o.rebootRequired(fn)
if err != nil {
err = xerrors.Errorf("Failed to detect the kernel reboot required: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to detect the kernel reboot required: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
}
@@ -283,13 +281,18 @@ func (o *redhatBase) scanPackages() (err error) {
updatable, err := o.scanUpdatablePackages()
if err != nil {
err = xerrors.Errorf("Failed to scan updatable packages: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to scan updatable packages: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
} else {
o.Packages.MergeNewVersion(updatable)
}
if o.getServerInfo().Mode.IsDeep() {
resolver := yumInstallDependentResolver{redhat: o}
resolver.scanDependentPkgsForUpdate()
}
return nil
}
@@ -723,3 +726,65 @@ func (o *redhatBase) parseDnfModuleList(stdout string) (labels []string, err err
}
return
}
type yumInstallDependentResolver struct {
redhat *redhatBase
}
func (o *yumInstallDependentResolver) scanDependentPkgsForUpdate() {
o.redhat.log.Infof("Detecting the dependencies of each packages when yum updating")
bar := pb.StartNew(len(o.redhat.Packages))
for name, pkg := range o.redhat.Packages {
bar.Increment()
if pkg.Version == pkg.NewVersion && pkg.Release == pkg.NewRelease {
continue
}
names, err := o.scanUpdatablePkgDeps(name)
if err != nil {
o.redhat.log.Warnf("err: %+v", xerrors.Errorf("Failed to scan dependent packages for update: %w", err))
o.redhat.warns = append(o.redhat.warns, err)
// Only warning this error
}
for _, n := range names {
pkg.DependenciesForUpdate = append(pkg.DependenciesForUpdate, n)
}
o.redhat.Packages[name] = pkg
}
bar.Finish()
return
}
func (o *yumInstallDependentResolver) scanUpdatablePkgDeps(name string) (depsPkgNames []string, err error) {
cmd := fmt.Sprintf("LANGUAGE=en_US.UTF-8 yum install --assumeno --cacheonly --quiet %s", name)
r := o.redhat.exec(cmd, true)
if !r.isSuccess(0, 1) {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
names := o.parseYumInstall(r.Stdout)
for _, n := range names {
if _, ok := o.redhat.Packages[n]; ok {
depsPkgNames = append(depsPkgNames, n)
}
}
return
}
func (o *yumInstallDependentResolver) parseYumInstall(stdout string) []string {
names, inDepsLines := []string{}, false
scanner := bufio.NewScanner(strings.NewReader(stdout))
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "Updating for dependencies:") {
inDepsLines = true
continue
}
if inDepsLines {
ss := strings.Fields(line)
if len(ss) == 0 {
break
}
names = append(names, ss[0])
}
}
return names
}

View File

@@ -641,3 +641,71 @@ kernel-3.10.0-1062.12.1.el7.x86_64 Sat 29 Feb 2020 12:09:00 PM UTC`,
})
}
}
func Test_redhatBase_parseYumInstall(t *testing.T) {
type fields struct {
base base
sudo rootPriv
}
type args struct {
stdout string
}
tests := []struct {
name string
fields fields
args args
wantPkgNames []string
}{
{
name: "ok",
fields: fields{
base: base{},
},
args: args{
stdout: `===========================================================================================================================================================
Package Arch Version Repository Size
===========================================================================================================================================================
Updating:
glibc x86_64 2.17-325.el7_9 updates 3.6 M
Updating for dependencies:
glibc-common x86_64 2.17-325.el7_9 updates 12 M
glibc-devel x86_64 2.17-325.el7_9 updates 1.1 M
glibc-headers x86_64 2.17-325.el7_9 updates 691 k
Transaction Summary
===========================================================================================================================================================
Upgrade 1 Package (+3 Dependent packages)
Exiting on user command
Your transaction was saved, rerun it with:
yum load-transaction /tmp/yum_save_tx.2021-10-25.08-24.1EXcRc.yumtx`,
},
wantPkgNames: []string{
"glibc-common",
"glibc-devel",
"glibc-headers",
},
},
{
name: "no deps",
fields: fields{
base: base{},
},
args: args{
stdout: `Package zlib-1.2.7-19.el7_9.x86_64 already installed and latest version`,
},
wantPkgNames: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &redhatBase{
base: tt.fields.base,
}
resolver := yumInstallDependentResolver{redhat: o}
if gotPkgNames := resolver.parseYumInstall(tt.args.stdout); !reflect.DeepEqual(gotPkgNames, tt.wantPkgNames) {
t.Errorf("redhatBase.parseYumInstall() = %v, want %v", gotPkgNames, tt.wantPkgNames)
}
})
}
}