Skip to content

Commit d3467ba

Browse files
committed
admin: add pre v4.8.0 admin command to delete OVAL vulns
The migration to delete OVAL vulnerabilities can take a while (10 mins plus depending on resources). This patch adds a command to pre-delete the vulnerabilities after adding the migration version entry. Signed-off-by: crozzy <[email protected]>
1 parent 5fb41ed commit d3467ba

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

cmd/clairctl/admin.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ var AdminCmd = &cli.Command{
4747
Usage: "create `idx_manifest_layer_layer_id` index in the `indexer` database",
4848
Action: adminPre473,
4949
},
50+
{
51+
Name: "v4.8.0",
52+
Aliases: []string{"4.8.0"},
53+
Description: "This task sets the matcher migration version to 13 to avert the migration deleting RHEL OVAL vulnerabilities.",
54+
Usage: "set matcher migration version to 13",
55+
Action: adminPre480,
56+
},
5057
},
5158
Before: otherVersion,
5259
},
@@ -64,6 +71,14 @@ var AdminCmd = &cli.Command{
6471
Usage: "delete pyupio vulns in from the matcher DB",
6572
Action: adminPost470,
6673
},
74+
{
75+
Name: "v4.8.0",
76+
Aliases: []string{"4.8.0"},
77+
Description: "This task deletes RHEL OVALv2 vulnerabilities from the database.\n" +
78+
"This could take a while so this command allows an operator to delete the vulnerabilities outside of migrations.\n",
79+
Usage: "delete RHEL OVALv2 vulnerabilities",
80+
Action: adminPost480,
81+
},
6782
},
6883
Before: otherVersion,
6984
},
@@ -476,3 +491,131 @@ func fromSemver(v *semver.Version) (out claircore.Version) {
476491
out.V[3] = int32(v.Patch())
477492
return out
478493
}
494+
495+
// Set matcher migration version to 13.
496+
func adminPre480(c *cli.Context) error {
497+
ctx := c.Context
498+
fi, err := os.Stat(c.Path("config"))
499+
switch {
500+
case !errors.Is(err, nil):
501+
return fmt.Errorf("bad config: %w", err)
502+
case fi.IsDir():
503+
return fmt.Errorf("bad config: is a directory")
504+
}
505+
cfg, err := loadConfig(c.Path("config"))
506+
if err != nil {
507+
return fmt.Errorf("error loading config: %w", err)
508+
}
509+
dsn := cfg.Matcher.ConnString
510+
511+
pgcfg, err := pgxpool.ParseConfig(dsn)
512+
if err != nil {
513+
return fmt.Errorf("error parsing dsn: %w", err)
514+
}
515+
zlog.Info(ctx).
516+
Str("host", pgcfg.ConnConfig.Host).
517+
Str("database", pgcfg.ConnConfig.Database).
518+
Str("user", pgcfg.ConnConfig.User).
519+
Uint16("port", pgcfg.ConnConfig.Port).
520+
Msg("using discovered connection params")
521+
522+
zlog.Debug(ctx).
523+
Msg("resizing pool to 1 connections")
524+
pgcfg.MaxConns = 1
525+
pool, err := pgxpool.ConnectConfig(ctx, pgcfg)
526+
if err != nil {
527+
return fmt.Errorf("error creating pool: %w", err)
528+
}
529+
defer pool.Close()
530+
if err := pool.Ping(ctx); err != nil {
531+
return fmt.Errorf("error connecting to database: %w", err)
532+
}
533+
534+
return pool.AcquireFunc(ctx, func(conn *pgxpool.Conn) error {
535+
const (
536+
setMatcherMigration = `INSERT INTO libvuln_migrations ("version") VALUES (13) ON CONFLICT DO NOTHING;`
537+
)
538+
if _, err := conn.Exec(ctx, setMatcherMigration); err != nil {
539+
return fmt.Errorf("error setting matcher migration: %w", err)
540+
}
541+
zlog.Debug(ctx).Msg("Set migration version done")
542+
zlog.Info(ctx).Msg("pre v4.8.0 admin done")
543+
return nil
544+
})
545+
}
546+
547+
// Attempt to remove RHEL OVALv2 vulnerabilities before v4.8.0 (where vulnerabilities come from VEX).
548+
func adminPost480(c *cli.Context) error {
549+
ctx := c.Context
550+
fi, err := os.Stat(c.Path("config"))
551+
switch {
552+
case !errors.Is(err, nil):
553+
return fmt.Errorf("bad config: %w", err)
554+
case fi.IsDir():
555+
return fmt.Errorf("bad config: is a directory")
556+
}
557+
cfg, err := loadConfig(c.Path("config"))
558+
if err != nil {
559+
return fmt.Errorf("error loading config: %w", err)
560+
}
561+
dsn := cfg.Matcher.ConnString
562+
563+
pgcfg, err := pgxpool.ParseConfig(dsn)
564+
if err != nil {
565+
return fmt.Errorf("error parsing dsn: %w", err)
566+
}
567+
zlog.Info(ctx).
568+
Str("host", pgcfg.ConnConfig.Host).
569+
Str("database", pgcfg.ConnConfig.Database).
570+
Str("user", pgcfg.ConnConfig.User).
571+
Uint16("port", pgcfg.ConnConfig.Port).
572+
Msg("using discovered connection params")
573+
574+
zlog.Debug(ctx).
575+
Msg("resizing pool to 2 connections")
576+
pgcfg.MaxConns = 2
577+
pool, err := pgxpool.ConnectConfig(ctx, pgcfg)
578+
if err != nil {
579+
return fmt.Errorf("error creating pool: %w", err)
580+
}
581+
defer pool.Close()
582+
if err := pool.Ping(ctx); err != nil {
583+
return fmt.Errorf("error connecting to database: %w", err)
584+
}
585+
586+
return pool.AcquireFunc(ctx, func(conn *pgxpool.Conn) error {
587+
const (
588+
selectUpdateOperations = `SELECT DISTINCT(updater) FROM update_operation WHERE updater ~ 'RHEL[5-9]-*'; `
589+
deleteOVALUO = `DELETE FROM update_operation WHERE updater = ANY($1::TEXT[]);`
590+
deleteOVALVulns = `DELETE FROM vuln where updater = ANY($1::TEXT[]);`
591+
)
592+
updaters := []string{}
593+
rows, err := conn.Query(ctx, selectUpdateOperations)
594+
if err != nil {
595+
return err
596+
}
597+
defer rows.Close()
598+
599+
var updater string
600+
for rows.Next() {
601+
if err := rows.Scan(&updater); err != nil {
602+
return err
603+
}
604+
updaters = append(updaters, updater)
605+
}
606+
if err := rows.Err(); err != nil {
607+
return err
608+
}
609+
zlog.Debug(ctx).Strs("updaters", updaters).Msg("Got updaters")
610+
if _, err := conn.Exec(ctx, deleteOVALUO, updaters); err != nil {
611+
return fmt.Errorf("error deleting OVAL update_operations: %w", err)
612+
}
613+
zlog.Debug(ctx).Msg("Delete update_operations done")
614+
if _, err := conn.Exec(ctx, deleteOVALVulns, updaters); err != nil {
615+
return fmt.Errorf("error deleting OVAL vulns: %w", err)
616+
}
617+
zlog.Debug(ctx).Msg("Delete vulns done")
618+
zlog.Info(ctx).Msg("post v4.8.0 admin done")
619+
return nil
620+
})
621+
}

0 commit comments

Comments
 (0)