Add support for Chainguard distro (#190)
Signed-off-by: Dan Luhring <dluhring@chainguard.dev>
This commit is contained in:
parent
953c694412
commit
77ea72500e
4
.github/workflows/update.yml
vendored
4
.github/workflows/update.yml
vendored
@ -111,6 +111,10 @@ jobs:
|
||||
name: Wolfi Secdb
|
||||
run: ./vuln-list-update -target wolfi
|
||||
|
||||
- if: always()
|
||||
name: Chainguard Secdb
|
||||
run: ./vuln-list-update -target chainguard
|
||||
|
||||
- if: always()
|
||||
name: Known Exploited Vulnerabilities Catalog
|
||||
run: ./vuln-list-update -target kevc
|
||||
|
@ -20,9 +20,13 @@ https://github.com/aquasecurity/vuln-list/
|
||||
$ vuln-list-update -h
|
||||
Usage of vuln-list-update:
|
||||
-target string
|
||||
update target (nvd, alpine, alpine-unfixed, redhat, redhat-oval, debian, debian-oval, ubuntu, amazon, oracle-oval, suse-cvrf, photon, arch-linux, ghsa, glad, cwe, osv, go-vulndb, mariner, kevc)
|
||||
update target (nvd, alpine, alpine-unfixed, redhat, redhat-oval, debian, debian-oval, ubuntu, amazon, oracle-oval, suse-cvrf, photon, arch-linux, ghsa, glad, cwe, osv, go-vulndb, mariner, kevc, wolfi, chainguard)
|
||||
-target-branch string
|
||||
alternative repository branch (only glad)
|
||||
-target-uri string
|
||||
alternative repository URI (only glad)
|
||||
-years string
|
||||
update years (only redhat)
|
||||
update years (only redhat)
|
||||
```
|
||||
|
||||
## Author
|
||||
|
73
chainguard/chainguard.go
Normal file
73
chainguard/chainguard.go
Normal file
@ -0,0 +1,73 @@
|
||||
package chainguard
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/vuln-list-update/alpine"
|
||||
"github.com/aquasecurity/vuln-list-update/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
chainguardDir = "chainguard"
|
||||
secdbURLBase = "https://packages.cgr.dev"
|
||||
secdbURLPath = "chainguard/security.json"
|
||||
)
|
||||
|
||||
type option func(c *Updater)
|
||||
|
||||
func WithVulnListDir(v string) option {
|
||||
return func(c *Updater) { c.vulnListDir = v }
|
||||
}
|
||||
|
||||
func WithAppFs(v afero.Fs) option {
|
||||
return func(c *Updater) { c.appFs = v }
|
||||
}
|
||||
|
||||
func WithBaseURL(v *url.URL) option {
|
||||
return func(c *Updater) { c.baseURL = v }
|
||||
}
|
||||
|
||||
type Updater struct {
|
||||
vulnListDir string
|
||||
appFs afero.Fs
|
||||
baseURL *url.URL
|
||||
}
|
||||
|
||||
func NewUpdater(options ...option) *Updater {
|
||||
u, _ := url.Parse(secdbURLBase)
|
||||
updater := &Updater{
|
||||
vulnListDir: utils.VulnListDir(),
|
||||
appFs: afero.NewOsFs(),
|
||||
baseURL: u,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(updater)
|
||||
}
|
||||
|
||||
return updater
|
||||
}
|
||||
|
||||
func (u *Updater) Update() error {
|
||||
dir := filepath.Join(u.vulnListDir, chainguardDir)
|
||||
log.Printf("Remove Chainguard directory %s", dir)
|
||||
if err := u.appFs.RemoveAll(dir); err != nil {
|
||||
return xerrors.Errorf("failed to remove Chainguard directory: %w", err)
|
||||
}
|
||||
if err := u.appFs.MkdirAll(dir, 0755); err != nil {
|
||||
return xerrors.Errorf("Chainguard mkdir error: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Fetching Chainguard data...")
|
||||
|
||||
alpineUpdater := alpine.NewUpdater(
|
||||
alpine.WithBaseURL(u.baseURL),
|
||||
alpine.WithVulnListDir(u.vulnListDir),
|
||||
alpine.WithAdvisoryDir(chainguardDir),
|
||||
alpine.WithAppFs(u.appFs))
|
||||
return alpineUpdater.Save("", secdbURLPath)
|
||||
}
|
115
chainguard/chainguard_test.go
Normal file
115
chainguard/chainguard_test.go
Normal file
@ -0,0 +1,115 @@
|
||||
package chainguard_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aquasecurity/vuln-list-update/chainguard"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var update = flag.Bool("update", false, "update golden files")
|
||||
|
||||
func TestUpdater_Update(t *testing.T) {
|
||||
type fields struct {
|
||||
appFs afero.Fs
|
||||
retry int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
fileNames map[string]string
|
||||
goldenFiles map[string]string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
appFs: afero.NewMemMapFs(),
|
||||
retry: 0,
|
||||
},
|
||||
fileNames: map[string]string{
|
||||
"/chainguard/security.json": "testdata/security.json",
|
||||
},
|
||||
goldenFiles: map[string]string{
|
||||
"/tmp/chainguard/chainguard/binutils.json": "testdata/golden/binutils.json",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "404",
|
||||
fields: fields{
|
||||
appFs: afero.NewMemMapFs(),
|
||||
retry: 0,
|
||||
},
|
||||
fileNames: map[string]string{
|
||||
"/": "testdata/index.html",
|
||||
},
|
||||
wantErr: "status code: 404",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fileName, ok := tt.fileNames[r.URL.Path]
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, r, fileName)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
baseURL, err := url.Parse(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
u := chainguard.NewUpdater(
|
||||
chainguard.WithVulnListDir("/tmp"),
|
||||
chainguard.WithBaseURL(baseURL),
|
||||
chainguard.WithAppFs(tt.fields.appFs))
|
||||
err = u.Update()
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), tt.wantErr)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
fileCount := 0
|
||||
err = afero.Walk(tt.fields.appFs, "/", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
fileCount++
|
||||
|
||||
actual, err := afero.ReadFile(tt.fields.appFs, path)
|
||||
assert.NoError(t, err, path)
|
||||
|
||||
goldenPath, ok := tt.goldenFiles[path]
|
||||
require.True(t, ok, path)
|
||||
if *update {
|
||||
err = ioutil.WriteFile(goldenPath, actual, 0666)
|
||||
require.NoError(t, err, goldenPath)
|
||||
}
|
||||
expected, err := ioutil.ReadFile(goldenPath)
|
||||
assert.NoError(t, err, goldenPath)
|
||||
|
||||
assert.JSONEq(t, string(expected), string(actual), path)
|
||||
|
||||
return nil
|
||||
})
|
||||
assert.Equal(t, len(tt.goldenFiles), fileCount)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
20
chainguard/testdata/golden/binutils.json
vendored
Normal file
20
chainguard/testdata/golden/binutils.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "binutils",
|
||||
"secfixes": {
|
||||
"2.39-r1": [
|
||||
"CVE-2022-38126"
|
||||
],
|
||||
"2.39-r2": [
|
||||
"CVE-2022-38533"
|
||||
],
|
||||
"2.39-r3": [
|
||||
"CVE-2022-38128"
|
||||
]
|
||||
},
|
||||
"apkurl": "{{urlprefix}}/{{reponame}}/{{arch}}/{{pkg.name}}-{{pkg.ver}}.apk",
|
||||
"archs": [
|
||||
"x86_64"
|
||||
],
|
||||
"urlprefix": "https://packages.cgr.dev",
|
||||
"reponame": "chainguard"
|
||||
}
|
26
chainguard/testdata/security.json
vendored
Normal file
26
chainguard/testdata/security.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"apkurl": "{{urlprefix}}/{{reponame}}/{{arch}}/{{pkg.name}}-{{pkg.ver}}.apk",
|
||||
"archs": [
|
||||
"x86_64"
|
||||
],
|
||||
"reponame": "chainguard",
|
||||
"urlprefix": "https://packages.cgr.dev",
|
||||
"packages": [
|
||||
{
|
||||
"pkg": {
|
||||
"name": "binutils",
|
||||
"secfixes": {
|
||||
"2.39-r1": [
|
||||
"CVE-2022-38126"
|
||||
],
|
||||
"2.39-r2": [
|
||||
"CVE-2022-38533"
|
||||
],
|
||||
"2.39-r3": [
|
||||
"CVE-2022-38128"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
12
main.go
12
main.go
@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/vuln-list-update/chainguard"
|
||||
"github.com/aquasecurity/vuln-list-update/kevc"
|
||||
"github.com/aquasecurity/vuln-list-update/wolfi"
|
||||
|
||||
@ -49,7 +50,7 @@ const (
|
||||
|
||||
var (
|
||||
target = flag.String("target", "", "update target (nvd, alpine, alpine-unfixed, redhat, redhat-oval, "+
|
||||
"debian, debian-oval, ubuntu, amazon, oracle-oval, suse-cvrf, photon, arch-linux, ghsa, glad, cwe, osv, go-vulndb, mariner, kevc, wolfi)")
|
||||
"debian, debian-oval, ubuntu, amazon, oracle-oval, suse-cvrf, photon, arch-linux, ghsa, glad, cwe, osv, go-vulndb, mariner, kevc, wolfi, chainguard)")
|
||||
years = flag.String("years", "", "update years (only redhat)")
|
||||
targetUri = flag.String("target-uri", "", "alternative repository URI (only glad)")
|
||||
targetBranch = flag.String("target-branch", "", "alternative repository branch (only glad)")
|
||||
@ -75,6 +76,7 @@ func run() error {
|
||||
url := fmt.Sprintf(repoURL, githubToken, repoOwner, repoName)
|
||||
|
||||
log.Printf("target repository is %s/%s\n", repoOwner, repoName)
|
||||
log.Printf("cloning/pulling into %s", utils.VulnListDir())
|
||||
|
||||
if _, err := gc.CloneOrPull(url, utils.VulnListDir(), "main", debug); err != nil {
|
||||
return xerrors.Errorf("clone or pull error: %w", err)
|
||||
@ -234,7 +236,13 @@ func run() error {
|
||||
if err := wu.Update(); err != nil {
|
||||
return xerrors.Errorf("Wolfi update error: %w", err)
|
||||
}
|
||||
commitMsg = "Wolfi Issue Tracker"
|
||||
commitMsg = "Wolfi Security Data"
|
||||
case "chainguard":
|
||||
cu := chainguard.NewUpdater()
|
||||
if err := cu.Update(); err != nil {
|
||||
return xerrors.Errorf("Chainguard update error: %w", err)
|
||||
}
|
||||
commitMsg = "Chainguard Security Data"
|
||||
default:
|
||||
return xerrors.New("unknown target")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user