feat(scan) detect the dependencies for each updatable packages
This commit is contained in:
5
go.mod
5
go.mod
@@ -16,7 +16,7 @@ require (
|
||||
github.com/briandowns/spinner v1.16.0 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
|
||||
github.com/cheggaaa/pb v1.0.27
|
||||
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
||||
github.com/emersion/go-smtp v0.14.0
|
||||
@@ -87,6 +87,7 @@ require (
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
|
||||
github.com/caarlos0/env/v6 v6.0.0 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
||||
@@ -142,7 +143,7 @@ require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -2013,8 +2013,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
|
||||
|
||||
@@ -84,6 +84,15 @@ type Package struct {
|
||||
Changelog *Changelog `json:"changelog,omitempty"`
|
||||
AffectedProcs []AffectedProcess `json:",omitempty"`
|
||||
NeedRestartProcs []NeedRestartProcess `json:",omitempty"`
|
||||
|
||||
// Dependencies are dependent packages
|
||||
Dependencies []string `json:",omitempty"`
|
||||
|
||||
// ReverseDependencies are packages which depend on this package
|
||||
ReverseDependencies []string `json:",omitempty"`
|
||||
|
||||
// DependenciesForUpdate are packages that needs to be updated together
|
||||
DependenciesForUpdate []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// FQPN returns Fully-Qualified-Package-Name
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user