Skip to content

Commit 87c24a9

Browse files
committed
admin: add command to update go packages with norm_version
There are a number of Go packages in the `package` table that do not have the needed norm_version which is required for Go matching. Signed-off-by: crozzy <[email protected]>
1 parent 55294aa commit 87c24a9

File tree

2 files changed

+158
-1
lines changed

2 files changed

+158
-1
lines changed

cmd/clairctl/admin.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package main
22

33
import (
4+
"context"
45
"errors"
56
"fmt"
67
"os"
78
"regexp"
89

10+
"github.com/Masterminds/semver"
911
"github.com/jackc/pgx/v4"
1012
"github.com/jackc/pgx/v4/pgxpool"
13+
"github.com/quay/claircore"
1114
"github.com/quay/zlog"
1215
"github.com/urfave/cli/v2"
1316
)
@@ -69,6 +72,15 @@ var AdminCmd = &cli.Command{
6972
Description: "Tasks that may be useful on occasion",
7073
Usage: "run one-off task",
7174
ArgsUsage: "\b",
75+
Subcommands: []*cli.Command{
76+
{
77+
Name: "update-golang-packages",
78+
Description: "This task will update the golang packages in the `package` table with the `norm_versions` and `norm_kind`.\n" +
79+
"Relevant package names are gleaned from the vulnerabilities in the matchers `vuln` table.\n\n",
80+
Usage: "update golang packages in the indexer DB",
81+
Action: updateGoPackages,
82+
},
83+
},
7284
},
7385
},
7486
}
@@ -282,3 +294,148 @@ func adminPre473(c *cli.Context) error {
282294
return nil
283295
})
284296
}
297+
298+
func updateGoPackages(c *cli.Context) error {
299+
const (
300+
getPackageNames = "SELECT DISTINCT package_name FROM vuln WHERE updater = 'osv/go'"
301+
getPackages = "SELECT id, version FROM package WHERE name = $1 and norm_version IS NULL"
302+
updatePackages = "UPDATE package SET norm_version=$1::int[], norm_kind=$2 WHERE id = $3 and norm_version IS NULL"
303+
)
304+
305+
ctx := c.Context
306+
fi, err := os.Stat(c.Path("config"))
307+
switch {
308+
case !errors.Is(err, nil):
309+
return fmt.Errorf("bad config: %w", err)
310+
case fi.IsDir():
311+
return fmt.Errorf("bad config: is a directory")
312+
}
313+
cfg, err := loadConfig(c.Path("config"))
314+
if err != nil {
315+
return fmt.Errorf("error loading config: %w", err)
316+
}
317+
matcherPool, err := createConnPool(ctx, cfg.Matcher.ConnString, 2)
318+
if err != nil {
319+
return fmt.Errorf("error creating indexer pool: %w", err)
320+
}
321+
defer matcherPool.Close()
322+
packageNames := []string{}
323+
err = matcherPool.AcquireFunc(ctx, func(conn *pgxpool.Conn) error {
324+
rows, err := conn.Query(ctx, getPackageNames)
325+
if err != nil {
326+
return fmt.Errorf("error getting package_name list: %w", err)
327+
}
328+
defer rows.Close()
329+
for rows.Next() {
330+
var p string
331+
err := rows.Scan(&p)
332+
if err != nil {
333+
return err
334+
}
335+
packageNames = append(packageNames, p)
336+
}
337+
return nil
338+
})
339+
if err != nil {
340+
return fmt.Errorf("could not get package names from matcher DB %w", err)
341+
}
342+
indexerPool, err := createConnPool(ctx, cfg.Indexer.ConnString, 2)
343+
if err != nil {
344+
return fmt.Errorf("error creating indexer pool: %w", err)
345+
}
346+
defer indexerPool.Close()
347+
348+
for _, p := range packageNames {
349+
err := indexerPool.AcquireFunc(ctx, func(conn *pgxpool.Conn) error {
350+
rows, err := conn.Query(ctx, getPackages, p)
351+
if err != nil {
352+
return fmt.Errorf("could not get packages for %s: %w", p, err)
353+
}
354+
defer rows.Close()
355+
for rows.Next() {
356+
var (
357+
id int64
358+
version string
359+
)
360+
err := rows.Scan(&id, &version)
361+
if err != nil {
362+
return err
363+
}
364+
ctx = zlog.ContextWithValues(ctx, "package_name", p, "version", version)
365+
zlog.Debug(ctx).
366+
Msg("working on version")
367+
368+
var nv claircore.Version
369+
ver, err := semver.NewVersion(version)
370+
switch {
371+
case errors.Is(err, nil):
372+
nv = fromSemver(ver)
373+
default:
374+
zlog.Warn(ctx).
375+
Err(err).
376+
Msg("error parsing semver")
377+
continue
378+
}
379+
var (
380+
vKind *string
381+
vNorm []int32
382+
)
383+
if nv.Kind != "" {
384+
vKind = &nv.Kind
385+
vNorm = nv.V[:]
386+
}
387+
388+
tag, err := indexerPool.Exec(ctx, updatePackages, vNorm, vKind, id)
389+
if err != nil {
390+
return fmt.Errorf("error updating packages: %w", err)
391+
}
392+
zlog.Info(ctx).
393+
Int64("package_id", id).
394+
Int64("rows affected", tag.RowsAffected()).
395+
Msg("successfully updated package row")
396+
}
397+
return nil
398+
})
399+
if err != nil {
400+
return fmt.Errorf("error acquiring pool conn: %w", err)
401+
}
402+
}
403+
return nil
404+
}
405+
406+
func createConnPool(ctx context.Context, dsn string, maxConns int32) (*pgxpool.Pool, error) {
407+
pgcfg, err := pgxpool.ParseConfig(dsn)
408+
if err != nil {
409+
return nil, fmt.Errorf("error parsing dsn: %w", err)
410+
}
411+
zlog.Info(ctx).
412+
Str("host", pgcfg.ConnConfig.Host).
413+
Str("database", pgcfg.ConnConfig.Database).
414+
Str("user", pgcfg.ConnConfig.User).
415+
Uint16("port", pgcfg.ConnConfig.Port).
416+
Msg("using discovered connection params")
417+
418+
zlog.Debug(ctx).
419+
Int32("pool size", maxConns).
420+
Msg("resizing pool")
421+
pgcfg.MaxConns = int32(maxConns)
422+
pool, err := pgxpool.ConnectConfig(ctx, pgcfg)
423+
if err != nil {
424+
return nil, fmt.Errorf("error creating pool: %w", err)
425+
}
426+
if err := pool.Ping(ctx); err != nil {
427+
return nil, fmt.Errorf("error connecting to database: %w", err)
428+
}
429+
return pool, nil
430+
}
431+
432+
// FromSemVer is copied from the gobin package. It converts
433+
// a semver.Version to a claircore.Version.
434+
func fromSemver(v *semver.Version) (out claircore.Version) {
435+
out.Kind = `semver`
436+
// Leave a leading epoch, for good measure.
437+
out.V[1] = int32(v.Major())
438+
out.V[2] = int32(v.Minor())
439+
out.V[3] = int32(v.Patch())
440+
return out
441+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/quay/clair/v4
33
go 1.20
44

55
require (
6+
github.com/Masterminds/semver v1.5.0
67
github.com/evanphx/json-patch/v5 v5.7.0
78
github.com/go-jose/go-jose/v3 v3.0.1
89
github.com/go-stomp/stomp/v3 v3.0.5
@@ -37,7 +38,6 @@ require (
3738
)
3839

3940
require (
40-
github.com/Masterminds/semver v1.5.0 // indirect
4141
github.com/beorn7/perks v1.0.1 // indirect
4242
github.com/cespare/xxhash/v2 v2.2.0 // indirect
4343
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect

0 commit comments

Comments
 (0)