Skip to content

Commit

Permalink
Introduce a script to generate a database usable by osv-offline
Browse files Browse the repository at this point in the history
This script largely builds on top of PR #89 with some necessary
modifications and additions.

The finalized script downloads and extracts the upstream OSV database
and generates additional files for container and RPM vulnerabilities.

Few modifications to the original scripts were necessary:
- Add a retry mechanism for getting the CSAF VEX files. Transient
  networking errors were common during testing and retries shold resolve
  them.
- Add internal ID (_id) to the OSV schema and set it to a random string.
  Every object in the nedb database must have this property.
- Split how the affectedList is generated between RPMs and containers.
- Duplicate affectedList entries for containers to also have registry
  registry.access.redhat.com. This is necessary because the CSAF VEX
  data only tracks images with registry.redhat.io.

This script is expected to be run periodically by a cronjob and
regenerate the DB files onto a persistent volume. Add the new script
to the mintmaker container, so that the cronjob can use the same image.

WARNING: The script now gets the list of advisories from changes.csv.
This is incorrect and should be changed to releases.csv when it becomes
available. The current state is for testing purposes only.
  • Loading branch information
querti committed Jan 24, 2025
1 parent 289fefb commit 91581ff
Show file tree
Hide file tree
Showing 12 changed files with 1,038 additions and 2 deletions.
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@ COPY go.sum go.sum
RUN go mod download

# Copy the go source
COPY cmd/main.go cmd/main.go
COPY cmd/manager/main.go cmd/main.go
COPY cmd/osv-generator/main.go cmd/osv-generator/main.go
COPY api/ api/
COPY pkg/ pkg/
COPY tools/ tools/
COPY internal/controller/ internal/controller/
COPY licenses/ licenses/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager cmd/main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o osv-generator cmd/osv-generator/main.go

# Use ubi-micro as minimal base image to package the manager binary
# See https://catalog.redhat.com/software/containers/ubi9/ubi-micro/615bdf943f6014fa45ae1b58
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4-1227.1725849298
WORKDIR /
COPY --from=builder /opt/app-root/src/manager .
COPY --from=builder /opt/app-root/src/osv-generator .

# It is mandatory to set these labels
LABEL name="Konflux Mintmaker"
Expand Down
File renamed without changes.
43 changes: 43 additions & 0 deletions cmd/osv-generator/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"flag"
"fmt"
"os"
"path/filepath"

osv_downloader "github.com/konflux-ci/mintmaker/tools/osv-downloader"
osv_generator "github.com/konflux-ci/mintmaker/tools/osv-generator"
)

func main() {
dockerFilename := flag.String("docker-filename", "docker.nedb", "Filename for the Docker DB file")
rpmFilename := flag.String("rpm-filename", "rpm.nedb", "Filename for the RPM DB file")
destDir := flag.String("destination-dir", "/tmp/osv-offline", "Destination directory for the OSV DB files")
days := flag.Int("days", 90, "Only advisories created in the last X days are included")

flag.Parse()
err := os.MkdirAll(*destDir, 0755)
if err != nil {
fmt.Println("failed to create destination path: ", err)
os.Exit(1)
}

err = osv_downloader.DownloadOsvDb(*destDir)
if err != nil {
fmt.Println("Downloading the OSV database has failed: ", err)
os.Exit(1)
}

osv_generator.GenerateOSV(filepath.Join(*destDir, *dockerFilename), true, *days)
if err != nil {
fmt.Println("Generating the container OSV database has failed: ", err)
os.Exit(1)
}
osv_generator.GenerateOSV(filepath.Join(*destDir, *rpmFilename), false, *days)
if err != nil {
fmt.Println("Generating the RPM OSV database has failed: ", err)
os.Exit(1)
}

}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ go 1.21

require (
github.com/bradleyfalzon/ghinstallation/v2 v2.10.0
github.com/dchest/uniuri v1.2.0
github.com/go-logr/logr v1.2.4
github.com/google/go-cmp v0.6.0
github.com/google/go-github/v45 v45.2.0
github.com/jarcoal/httpmock v1.3.1
github.com/konflux-ci/application-api v0.0.0-20240527211352-be061932d497
github.com/onsi/ginkgo/v2 v2.11.0
github.com/onsi/gomega v1.27.10
Expand Down Expand Up @@ -36,7 +39,6 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-github/v60 v60.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
Expand Down Expand Up @@ -74,6 +76,8 @@ github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
Expand All @@ -95,6 +99,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
96 changes: 96 additions & 0 deletions tools/osv-downloader/download_osv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package osv_downloader

import (
"archive/zip"
"context"
"fmt"
"io"
"net/http"
"os"
"path/filepath"

"github.com/google/go-github/v45/github"
)

// Download and extract the upstream OSV database
func DownloadOsvDb(path string) error {
fmt.Println("getting osv-offline.zip URL from Github")
client := github.NewClient(nil)
release, _, err := client.Repositories.GetLatestRelease(context.Background(), "renovatebot", "osv-offline")
if err != nil {
return fmt.Errorf("error when accessing latest osv-offline release: %s", err)
}

var zipped_db *github.ReleaseAsset
for _, asset := range release.Assets {
if *asset.Name == "osv-offline.zip" {
zipped_db = asset
break
}
}
if zipped_db == nil {
return fmt.Errorf("osv-offline.zip asset couldn't be found in the latest release")
}
archive_path := filepath.Join(path, "osv-offline.zip")
err = downloadFile(*zipped_db.BrowserDownloadURL, archive_path)
if err != nil {
return fmt.Errorf("error when downloading the osv-offline file: %s", err)
}
err = unzipFile(archive_path, path)
if err != nil {
return fmt.Errorf("error when unzipping the osv-offline file: %s", err)
}
return nil
}

func downloadFile(url string, filepath string) error {
fmt.Println("downloading osv-offline database")
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()

out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()

_, err = io.Copy(out, resp.Body)
return err
}

func unzipFile(archive_path string, destination string) error {
fmt.Println("unzipping osv-offline database")
archive, err := zip.OpenReader(archive_path)
if err != nil {
return err
}
defer archive.Close()

for _, file := range archive.File {
filePath := filepath.Join(destination, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(filePath, os.ModePerm)
continue
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
destFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
fileInArchive, err := file.Open()
if err != nil {
return err
}
if _, err := io.Copy(destFile, fileInArchive); err != nil {
return err
}
destFile.Close()
fileInArchive.Close()
}
return nil
}
40 changes: 40 additions & 0 deletions tools/osv-generator/csaf_vex_vulnerability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package osv_generator

type VEX struct {
Document struct {
AggregateSeverity struct {
Text string `json:"text"`
} `json:"aggregate_severity"`
} `json:"document"`
Vulnerabilities []*Vulnerability `json:"vulnerabilities"`
ProductTree struct {
Branches []struct {
Branches []struct {
Category string `json:"category"`
Branches []struct {
Product struct {
ProductIdentificationHelper struct {
Purl string `json:"purl"`
} `json:"product_identification_helper"`
} `json:"product"`
} `json:"branches"`
} `json:"branches"`
} `json:"branches"`
} `json:"product_tree"`
}

type Vulnerability struct {
Cve string `json:"cve"`
DiscoveryDate string `json:"discovery_date"`
Cwe struct {
Id string `json:"id"`
} `json:"cwe"`
References []struct {
Category string `json:"category"`
Url string `json:"url"`
} `json:"references"`
Notes []struct {
Category string `json:"category"`
Text string `json:"text"`
} `json:"notes"`
}
Loading

0 comments on commit 91581ff

Please sign in to comment.