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
|
name: Wolfi Secdb
|
||||||
run: ./vuln-list-update -target wolfi
|
run: ./vuln-list-update -target wolfi
|
||||||
|
|
||||||
|
- if: always()
|
||||||
|
name: Chainguard Secdb
|
||||||
|
run: ./vuln-list-update -target chainguard
|
||||||
|
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Known Exploited Vulnerabilities Catalog
|
name: Known Exploited Vulnerabilities Catalog
|
||||||
run: ./vuln-list-update -target kevc
|
run: ./vuln-list-update -target kevc
|
||||||
|
@ -20,9 +20,13 @@ https://github.com/aquasecurity/vuln-list/
|
|||||||
$ vuln-list-update -h
|
$ vuln-list-update -h
|
||||||
Usage of vuln-list-update:
|
Usage of vuln-list-update:
|
||||||
-target string
|
-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
|
-years string
|
||||||
update years (only redhat)
|
update years (only redhat)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Author
|
## 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"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/vuln-list-update/chainguard"
|
||||||
"github.com/aquasecurity/vuln-list-update/kevc"
|
"github.com/aquasecurity/vuln-list-update/kevc"
|
||||||
"github.com/aquasecurity/vuln-list-update/wolfi"
|
"github.com/aquasecurity/vuln-list-update/wolfi"
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
target = flag.String("target", "", "update target (nvd, alpine, alpine-unfixed, redhat, redhat-oval, "+
|
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)")
|
years = flag.String("years", "", "update years (only redhat)")
|
||||||
targetUri = flag.String("target-uri", "", "alternative repository URI (only glad)")
|
targetUri = flag.String("target-uri", "", "alternative repository URI (only glad)")
|
||||||
targetBranch = flag.String("target-branch", "", "alternative repository branch (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)
|
url := fmt.Sprintf(repoURL, githubToken, repoOwner, repoName)
|
||||||
|
|
||||||
log.Printf("target repository is %s/%s\n", 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 {
|
if _, err := gc.CloneOrPull(url, utils.VulnListDir(), "main", debug); err != nil {
|
||||||
return xerrors.Errorf("clone or pull error: %w", err)
|
return xerrors.Errorf("clone or pull error: %w", err)
|
||||||
@ -234,7 +236,13 @@ func run() error {
|
|||||||
if err := wu.Update(); err != nil {
|
if err := wu.Update(); err != nil {
|
||||||
return xerrors.Errorf("Wolfi update error: %w", err)
|
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:
|
default:
|
||||||
return xerrors.New("unknown target")
|
return xerrors.New("unknown target")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user