feat: add k8s cve collector (#239)
This commit is contained in:
parent
26dae1a5f7
commit
b98364d3e4
41
.github/workflows/k8s.yml
vendored
Normal file
41
.github/workflows/k8s.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: Update vuln-list-k8s repo
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 */6 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
name: Update vuln-list-k8s
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
VULN_LIST_DIR: "vuln-list-k8s"
|
||||||
|
REPOSITORY_OWNER: ${{ github.repository_owner }}
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Check out vuln-list-k8s repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ env.REPOSITORY_OWNER }}/${{ env.VULN_LIST_DIR }}
|
||||||
|
token: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
path: ${{ env.VULN_LIST_DIR }}
|
||||||
|
|
||||||
|
- name: Setup github user email and name
|
||||||
|
run: |
|
||||||
|
git config --global user.email "action@github.com"
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
|
||||||
|
- name: Compile vuln-list-update
|
||||||
|
run: go build -o vuln-list-update .
|
||||||
|
|
||||||
|
- if: always()
|
||||||
|
name: K8s official vulnerability advisory
|
||||||
|
run: ./create_pr.sh k8s
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ vuln-list-update
|
|||||||
|
|
||||||
# MacOs
|
# MacOs
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vscode
|
||||||
|
46
create_pr.sh
Executable file
46
create_pr.sh
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TARGET=$1
|
||||||
|
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo "target required"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
./vuln-list-update -vuln-list-dir "$VULN_LIST_DIR" -target "$TARGET"
|
||||||
|
|
||||||
|
cd "$VULN_LIST_DIR" || exit 1
|
||||||
|
|
||||||
|
if [[ -n $(git status --porcelain) ]]; then
|
||||||
|
# List changed files
|
||||||
|
CHANGED_FILES=$(git ls-files . --exclude-standard --others | grep "CVE")
|
||||||
|
REPO="$REPOSITORY_OWNER/$VULN_LIST_DIR"
|
||||||
|
BASE_BRANCH="main"
|
||||||
|
# Loop through changed files and create PRs
|
||||||
|
for FILE in $CHANGED_FILES; do
|
||||||
|
|
||||||
|
BRANCH_NAME=$(echo "$FILE" | tr / -)
|
||||||
|
PR_TITLE="Update $FILE"
|
||||||
|
PR_BODY="This PR updates $FILE"
|
||||||
|
|
||||||
|
# Check if a PR with the same branch name already exists
|
||||||
|
OPEN_PR_COUNT=$(gh pr list --state open --base $BASE_BRANCH --repo "$REPO" | grep "$FILE" | wc -l)
|
||||||
|
|
||||||
|
if [ "$OPEN_PR_COUNT" != 0 ]; then
|
||||||
|
echo "PR for $FILE already exists, skipping."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create a new branch and push it
|
||||||
|
git checkout -b "$BRANCH_NAME"
|
||||||
|
echo "$FILE"
|
||||||
|
git add "$FILE"
|
||||||
|
git commit -m "Update $FILE"
|
||||||
|
|
||||||
|
git push origin "$BRANCH_NAME" --force
|
||||||
|
# Create a new pull request using gh
|
||||||
|
gh pr create --base "$BASE_BRANCH" --head "$BRANCH_NAME" --title "$PR_TITLE" --body "$PR_BODY" --repo "$REPO"
|
||||||
|
|
||||||
|
git checkout $BASE_BRANCH
|
||||||
|
done
|
||||||
|
fi
|
4
go.mod
4
go.mod
@ -4,9 +4,12 @@ go 1.20
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.8.0
|
github.com/PuerkitoBio/goquery v1.8.0
|
||||||
|
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||||
|
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492
|
||||||
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83
|
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83
|
||||||
github.com/cheggaaa/pb v2.0.7+incompatible
|
github.com/cheggaaa/pb v2.0.7+incompatible
|
||||||
github.com/cheggaaa/pb/v3 v3.1.4
|
github.com/cheggaaa/pb/v3 v3.1.4
|
||||||
|
github.com/goark/go-cvss v1.6.6
|
||||||
github.com/hashicorp/go-getter v1.7.2
|
github.com/hashicorp/go-getter v1.7.2
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-jsonpointer v0.0.1
|
github.com/mattn/go-jsonpointer v0.0.1
|
||||||
@ -35,6 +38,7 @@ require (
|
|||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
|
github.com/goark/errs v1.1.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
12
go.sum
12
go.sum
@ -198,6 +198,10 @@ github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAU
|
|||||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
||||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
|
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 h1:vmXNl+HDfqqXgr0uY1UgK1GAhps8nbAAtqHNBcgyf+4=
|
||||||
|
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46/go.mod h1:olhPNdiiAAMiSujemd1O/sc6GcyePr23f/6uGKtthNg=
|
||||||
|
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 h1:rcEG5HI490FF0a7zuvxOxen52ddygCfNVjP0XOCMl+M=
|
||||||
|
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
|
||||||
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8=
|
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8=
|
||||||
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
|
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
|
||||||
github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo=
|
github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo=
|
||||||
@ -225,6 +229,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
|
|||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -247,6 +252,10 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
|||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/goark/errs v1.1.0 h1:FKnyw4LVyRADIjM8Nj0Up6r0/y5cfADvZAd1E+tthXE=
|
||||||
|
github.com/goark/errs v1.1.0/go.mod h1:TtaPEoadm2mzqzfXdkkfpN2xuniCFm2q4JH+c1qzaqw=
|
||||||
|
github.com/goark/go-cvss v1.6.6 h1:WJFuIWqmAw1Ilb9USv0vuX+nYzOWJp8lIujseJ/y3sU=
|
||||||
|
github.com/goark/go-cvss v1.6.6/go.mod h1:H3qbfUSUlV7XtA3EwWNunvXz6OySwWHOuO+R6ZPMQPI=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@ -407,10 +416,12 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
|||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0 h1:T9uus1QvcPgeLShS30YOnnzk3r9Vvygp45muhlrufgY=
|
github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0 h1:T9uus1QvcPgeLShS30YOnnzk3r9Vvygp45muhlrufgY=
|
||||||
github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo=
|
github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo=
|
||||||
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk=
|
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk=
|
||||||
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg=
|
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA=
|
github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA=
|
||||||
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
|
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
|
||||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||||
@ -434,6 +445,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
280
k8s/k8s.go
Normal file
280
k8s/k8s.go
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
package k8s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/vuln-list-update/osv"
|
||||||
|
"github.com/aquasecurity/vuln-list-update/utils"
|
||||||
|
uu "github.com/aquasecurity/vuln-list-update/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
k8svulnDBURL = "https://kubernetes.io/docs/reference/issues-security/official-cve-feed/index.json"
|
||||||
|
vulnListRepoTarBall = "https://api.github.com/repos/aquasecurity/vuln-list-k8s/tarball"
|
||||||
|
mitreURL = "https://cveawg.mitre.org/api/cve"
|
||||||
|
cveList = "https://www.cve.org/"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VulnDB struct {
|
||||||
|
Cves []*osv.OSV
|
||||||
|
}
|
||||||
|
|
||||||
|
type CVE struct {
|
||||||
|
Items []Item `json:"items,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Summary string `json:"summary,omitempty"`
|
||||||
|
ContentText string `json:"content_text,omitempty"`
|
||||||
|
DatePublished string `json:"date_published,omitempty"`
|
||||||
|
ExternalURL string `json:"external_url,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Collect() (*VulnDB, error) {
|
||||||
|
response, err := http.Get(k8svulnDBURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
var db CVE
|
||||||
|
if err = json.NewDecoder(response.Body).Decode(&db); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cvesMap, err := getExitingCvesToModifiedMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ParseVulnDBData(db, cvesMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// excludeNonCoreComponentsCves exclude cves with missing data or non k8s core components
|
||||||
|
excludeNonCoreComponentsCves = "CVE-2019-11255,CVE-2020-10749,CVE-2020-8554"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Update() error {
|
||||||
|
if err := update(); err != nil {
|
||||||
|
return xerrors.Errorf("error in k8s update: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func update() error {
|
||||||
|
log.Printf("Fetching k8s cves")
|
||||||
|
|
||||||
|
k8sdb, err := Collect()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, cve := range k8sdb.Cves {
|
||||||
|
if err = uu.Write(filepath.Join(uu.VulnListDir(), "upstream", fmt.Sprintf("%s.json", cve.ID)), cve); err != nil {
|
||||||
|
return xerrors.Errorf("failed to save k8s CVE detail: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseVulnDBData(db CVE, cvesMap map[string]string) (*VulnDB, error) {
|
||||||
|
var fullVulnerabilities []*osv.OSV
|
||||||
|
for _, item := range db.Items {
|
||||||
|
for _, cveID := range getMultiIDs(item.ID) {
|
||||||
|
// check if the current cve is older than the existing one on the vuln-list-k8s repo
|
||||||
|
if strings.Contains(excludeNonCoreComponentsCves, item.ID) || olderCve(cveID, item.DatePublished, cvesMap) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vulnerability, err := parseMitreCve(item.ExternalURL, cveID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if cveMissingImportantData(vulnerability) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
descComponent := getComponentFromDescription(item.ContentText, vulnerability.Package)
|
||||||
|
fullVulnerabilities = append(fullVulnerabilities, &osv.OSV{
|
||||||
|
ID: cveID,
|
||||||
|
Modified: item.DatePublished,
|
||||||
|
Published: item.DatePublished,
|
||||||
|
Summary: item.Summary,
|
||||||
|
Details: vulnerability.Description,
|
||||||
|
Affected: getAffectedEvents(vulnerability.versions, getComponentName(descComponent, vulnerability.Package), vulnerability.CvssV3),
|
||||||
|
References: []osv.Reference{{Url: item.URL}, {Url: item.ExternalURL}},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := validateCvesData(fullVulnerabilities)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &VulnDB{fullVulnerabilities}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAffectedEvents(v []*Version, p string, cvss Cvssv3) []osv.Affected {
|
||||||
|
affected := make([]osv.Affected, 0)
|
||||||
|
for _, av := range v {
|
||||||
|
if len(av.Introduced) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if av.Introduced == "0.0.0" {
|
||||||
|
av.Introduced = "0"
|
||||||
|
}
|
||||||
|
events := make([]osv.Event, 0)
|
||||||
|
ranges := make([]osv.Range, 0)
|
||||||
|
if len(av.Introduced) > 0 {
|
||||||
|
events = append(events, osv.Event{Introduced: av.Introduced})
|
||||||
|
}
|
||||||
|
if len(av.Fixed) > 0 {
|
||||||
|
events = append(events, osv.Event{Fixed: av.Fixed})
|
||||||
|
} else if len(av.LastAffected) > 0 {
|
||||||
|
events = append(events, osv.Event{LastAffected: av.LastAffected})
|
||||||
|
} else if len(av.Introduced) > 0 && len(av.LastAffected) == 0 && len(av.Fixed) == 0 {
|
||||||
|
events = append(events, osv.Event{LastAffected: av.Introduced})
|
||||||
|
}
|
||||||
|
ranges = append(ranges, osv.Range{
|
||||||
|
Events: events,
|
||||||
|
})
|
||||||
|
affected = append(affected, osv.Affected{Ranges: ranges, Package: osv.Package{Name: p, Ecosystem: "kubernetes"}, Severities: []osv.Severity{{Type: cvss.Type, Score: cvss.Vector}}})
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
func getComponentName(k8sComponent string, mitreComponent string) string {
|
||||||
|
if len(k8sComponent) == 0 {
|
||||||
|
k8sComponent = mitreComponent
|
||||||
|
}
|
||||||
|
if strings.ToLower(mitreComponent) != "kubernetes" {
|
||||||
|
k8sComponent = mitreComponent
|
||||||
|
}
|
||||||
|
return strings.ToLower(fmt.Sprintf("%s/%s", upstreamOrgByName(k8sComponent), upstreamRepoByName(k8sComponent)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateCvesData(cves []*osv.OSV) error {
|
||||||
|
var result error
|
||||||
|
for _, cve := range cves {
|
||||||
|
if len(cve.ID) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nid is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
if len(cve.Published) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nCreatedAt is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
if len(cve.Summary) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nSummary is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
for _, af := range cve.Affected {
|
||||||
|
if len(strings.TrimPrefix(af.Package.Name, upstreamOrgByName(af.Package.Name))) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nComponent is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(cve.Details) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nDescription is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
if len(cve.Affected) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nAffected Version is missing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
if len(cve.Affected) > 0 {
|
||||||
|
for _, v := range cve.Affected {
|
||||||
|
for _, s := range v.Severities {
|
||||||
|
if len(s.Type) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nVector is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, r := range v.Ranges {
|
||||||
|
for i := 1; i < len(r.Events); i++ {
|
||||||
|
if len(r.Events[i-1].Introduced) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nAffectedVersion Introduced is missing from cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
if len(r.Events[i].Fixed) == 0 && len(r.Events[i].LastAffected) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nAffectedVersion Fixed and LastAffected are missing from cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(cve.References) == 0 {
|
||||||
|
result = errors.Join(result, fmt.Errorf("\nUrls is mssing on cve #%s", cve.ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func cveMissingImportantData(vulnerability *Cve) bool {
|
||||||
|
return len(vulnerability.versions) == 0 ||
|
||||||
|
len(vulnerability.Package) == 0 ||
|
||||||
|
len(vulnerability.CvssV3.Vector) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExitingCvesToModifiedMap get the existing cves from vuln-list-k8s repo and map it to cve id and last updated
|
||||||
|
func getExitingCvesToModifiedMap() (map[string]string, error) {
|
||||||
|
response, err := http.Get(vulnListRepoTarBall)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
return cveIDToModifiedMap(utils.VulnListDir())
|
||||||
|
}
|
||||||
|
|
||||||
|
// cveIDToModifiedMap read existing cves from vulnList folder and map it to cve id and last updated
|
||||||
|
func cveIDToModifiedMap(cveFolderPath string) (map[string]string, error) {
|
||||||
|
mapCveTime := make(map[string]string)
|
||||||
|
if _, err := os.Stat(cveFolderPath); os.IsNotExist(err) {
|
||||||
|
return mapCveTime, nil
|
||||||
|
}
|
||||||
|
fileInfo, err := os.ReadDir(cveFolderPath)
|
||||||
|
if err != nil {
|
||||||
|
return mapCveTime, err
|
||||||
|
}
|
||||||
|
for _, file := range fileInfo {
|
||||||
|
if file.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b, err := os.ReadFile(filepath.Join(cveFolderPath, file.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var cve osv.OSV
|
||||||
|
err = json.Unmarshal([]byte(strings.ReplaceAll(string(b), "\n", "")), &cve)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mapCveTime[cve.ID] = cve.Modified
|
||||||
|
}
|
||||||
|
return mapCveTime, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// olderCve check if the current cve is older than the existing one
|
||||||
|
func olderCve(cveID string, currentCVEUpdated string, existCveLastUpdated map[string]string) bool {
|
||||||
|
if len(existCveLastUpdated) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var lastUpdated string
|
||||||
|
var ok bool
|
||||||
|
if lastUpdated, ok = existCveLastUpdated[cveID]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
existLastUpdated, err := time.Parse(time.RFC3339, lastUpdated)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
currentLastUpdated, err := time.Parse(time.RFC3339, currentCVEUpdated)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// check if the current collcted cve is older or same as the existing one
|
||||||
|
if currentLastUpdated.Before(existLastUpdated) || currentLastUpdated == existLastUpdated {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
62
k8s/k8s_test.go
Normal file
62
k8s/k8s_test.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package k8s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ParseVulneDB(t *testing.T) {
|
||||||
|
b, err := os.ReadFile("./testdata/k8s-db.json")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
var bi CVE
|
||||||
|
err = json.Unmarshal(b, &bi)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
kvd, err := ParseVulnDBData(bi, map[string]string{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = validateCvesData(kvd.Cves)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
gotVulnDB, err := json.Marshal(kvd.Cves)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
wantVulnDB, err := os.ReadFile("./testdata/expected-vulndb.json")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, string(wantVulnDB), string(gotVulnDB))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_cveIDToModifiedMap(t *testing.T) {
|
||||||
|
t.Run("valid folder with cve", func(t *testing.T) {
|
||||||
|
tm, err := cveIDToModifiedMap("./testdata/happy/upstream")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tm["CVE-2018-1002102"], "2018-11-26T11:07:36Z")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("non existing folder", func(t *testing.T) {
|
||||||
|
tm, err := cveIDToModifiedMap("./test")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, len(tm) == 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_OlderCve(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Name string
|
||||||
|
currentCveID string
|
||||||
|
currentModified string
|
||||||
|
cveModified map[string]string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{Name: "match CVE but older Modified", currentCveID: "CVE-2018-1002102", currentModified: "2018-11-25T11:07:36Z", cveModified: map[string]string{"CVE-2018-1002102": "2018-11-26T11:07:36Z"}, want: true},
|
||||||
|
{Name: "match CVE but older not Modified", currentCveID: "CVE-2018-1002102", currentModified: "2018-11-27T11:07:36Z", cveModified: map[string]string{"CVE-2018-1002102": "2018-11-26T11:07:36Z"}, want: false},
|
||||||
|
{Name: "match CVE same time", currentCveID: "CVE-2018-1002102", currentModified: "2018-11-27T11:07:36Z", cveModified: map[string]string{"CVE-2018-1002102": "2018-11-27T11:07:36Z"}, want: true},
|
||||||
|
{Name: "no existing cve", currentCveID: "CVE-2018-1002102", currentModified: "2018-11-27T11:07:36Z", cveModified: map[string]string{}, want: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.Name, func(t *testing.T) {
|
||||||
|
got := olderCve(tt.currentCveID, tt.currentModified, tt.cveModified)
|
||||||
|
assert.Equal(t, got, tt.want)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
286
k8s/mitre.go
Normal file
286
k8s/mitre.go
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package k8s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
version "github.com/aquasecurity/go-version/pkg/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MitreCVE struct {
|
||||||
|
CveMetadata CveMetadata
|
||||||
|
Containers Containers
|
||||||
|
}
|
||||||
|
|
||||||
|
type Containers struct {
|
||||||
|
Cna struct {
|
||||||
|
Affected []struct {
|
||||||
|
Product string
|
||||||
|
Vendor string
|
||||||
|
Versions []*MitreVersion
|
||||||
|
}
|
||||||
|
Descriptions []Descriptions
|
||||||
|
Metrics []struct {
|
||||||
|
CvssV3_1 struct {
|
||||||
|
VectorString string
|
||||||
|
}
|
||||||
|
CvssV3_0 struct {
|
||||||
|
VectorString string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MitreVersion struct {
|
||||||
|
Status string
|
||||||
|
Version string
|
||||||
|
LessThanOrEqual string
|
||||||
|
LessThan string
|
||||||
|
VersionType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CveMetadata struct {
|
||||||
|
CveId string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Descriptions struct {
|
||||||
|
Lang string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cve struct {
|
||||||
|
Description string
|
||||||
|
versions []*Version
|
||||||
|
CvssV3 Cvssv3
|
||||||
|
Package string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cvssv3 struct {
|
||||||
|
Vector string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
Introduced string `json:"introduced,omitempty"`
|
||||||
|
Fixed string `json:"fixed,omitempty"`
|
||||||
|
LastAffected string `json:"last_affected,omitempty"`
|
||||||
|
FixedIndex int `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMitreCve(externalURL string, cveID string) (*Cve, error) {
|
||||||
|
if !strings.HasPrefix(externalURL, cveList) {
|
||||||
|
// if no external url provided, return empty vulnerability to be skipped
|
||||||
|
return &Cve{}, nil
|
||||||
|
}
|
||||||
|
response, err := http.Get(fmt.Sprintf("%s/%s", mitreURL, cveID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
var cve MitreCVE
|
||||||
|
if err = json.NewDecoder(response.Body).Decode(&cve); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
vulnerableVersions := make([]*Version, 0)
|
||||||
|
var component string
|
||||||
|
var requireMerge bool
|
||||||
|
for _, a := range cve.Containers.Cna.Affected {
|
||||||
|
if len(component) == 0 {
|
||||||
|
component = strings.ToLower(a.Product)
|
||||||
|
}
|
||||||
|
for _, sv := range a.Versions {
|
||||||
|
if sv.Status != "affected" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var introduce, lastAffected, fixed string
|
||||||
|
v, ok := sanitizedVersions(sv)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case len(v.LessThan) > 0:
|
||||||
|
if strings.HasSuffix(v.LessThan, ".0") {
|
||||||
|
v.Version = "0"
|
||||||
|
}
|
||||||
|
introduce, fixed = updateVersions(v.LessThan, v.Version)
|
||||||
|
case len(v.LessThanOrEqual) > 0:
|
||||||
|
introduce, lastAffected = updateVersions(v.LessThanOrEqual, v.Version)
|
||||||
|
case minorVersion(v.Version):
|
||||||
|
requireMerge = true
|
||||||
|
introduce = v.Version
|
||||||
|
default:
|
||||||
|
introduce, lastAffected = extractRangeVersions(v.Version)
|
||||||
|
}
|
||||||
|
vulnerableVersions = append(vulnerableVersions, &Version{
|
||||||
|
Introduced: introduce,
|
||||||
|
Fixed: fixed,
|
||||||
|
LastAffected: lastAffected,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if requireMerge {
|
||||||
|
vulnerableVersions, err = mergeVersionRange(vulnerableVersions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vector, vectorType := getMetrics(cve)
|
||||||
|
description := getDescription(cve.Containers.Cna.Descriptions)
|
||||||
|
return &Cve{
|
||||||
|
Description: description,
|
||||||
|
CvssV3: Cvssv3{
|
||||||
|
Vector: vector,
|
||||||
|
Type: vectorType,
|
||||||
|
},
|
||||||
|
Package: getComponentFromDescription(description, component),
|
||||||
|
versions: vulnerableVersions,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizedVersions(v *MitreVersion) (*MitreVersion, bool) {
|
||||||
|
if strings.Contains(v.Version, "n/a") && len(v.LessThan) == 0 && len(v.LessThanOrEqual) == 0 {
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
if (v.LessThanOrEqual == "unspecified" || v.LessThan == "unspecified") && len(v.Version) > 0 {
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
// example https://cveawg.mitre.org/api/cve/CVE-2023-2727
|
||||||
|
if len(v.LessThanOrEqual) > 0 && v.LessThanOrEqual == "<=" {
|
||||||
|
v.LessThanOrEqual = v.Version
|
||||||
|
} else if len(v.LessThan) > 0 {
|
||||||
|
switch {
|
||||||
|
// example https://cveawg.mitre.org/api/cve/CVE-2019-11244
|
||||||
|
case strings.HasSuffix(strings.TrimSpace(v.LessThan), "*"):
|
||||||
|
v.Version = strings.TrimSpace(strings.ReplaceAll(v.LessThan, "*", ""))
|
||||||
|
v.LessThan = ""
|
||||||
|
}
|
||||||
|
} else if len(v.Version) > 0 {
|
||||||
|
switch {
|
||||||
|
// example https://cveawg.mitre.org/api/cve/CVE-2020-8566
|
||||||
|
case strings.HasPrefix(v.Version, "< "):
|
||||||
|
v.LessThan = strings.TrimPrefix(v.Version, "< ")
|
||||||
|
// example https://cveawg.mitre.org/api/cve/CVE-2020-8565
|
||||||
|
case strings.HasPrefix(v.Version, "<= "):
|
||||||
|
v.LessThanOrEqual = strings.TrimPrefix(v.Version, "<= ")
|
||||||
|
//example https://cveawg.mitre.org/api/cve/CVE-2019-11247
|
||||||
|
case strings.HasPrefix(strings.TrimSpace(v.Version), "prior to"):
|
||||||
|
priorToVersion := strings.TrimSpace(strings.TrimPrefix(v.Version, "prior to"))
|
||||||
|
if minorVersion(priorToVersion) {
|
||||||
|
priorToVersion = priorToVersion + ".0"
|
||||||
|
v.Version = priorToVersion
|
||||||
|
}
|
||||||
|
v.LessThan = priorToVersion
|
||||||
|
// all version is vulnerable : https://cveawg.mitre.org/api/cve/CVE-2017-1002101
|
||||||
|
case strings.HasSuffix(strings.TrimSpace(v.Version), ".x"):
|
||||||
|
v.Version = strings.TrimSpace(strings.ReplaceAll(v.Version, ".x", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &MitreVersion{
|
||||||
|
Version: trimString(v.Version, []string{"v", "V"}),
|
||||||
|
LessThanOrEqual: trimString(v.LessThanOrEqual, []string{"v", "V"}),
|
||||||
|
LessThan: trimString(v.LessThan, []string{"v", "V"}),
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDescription(descriptions []Descriptions) string {
|
||||||
|
for _, d := range descriptions {
|
||||||
|
if d.Lang == "en" {
|
||||||
|
return d.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type byVersion []*Version
|
||||||
|
|
||||||
|
func (s byVersion) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s byVersion) Swap(i, j int) {
|
||||||
|
s[i], s[j] = s[j], s[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s byVersion) Less(i, j int) bool {
|
||||||
|
v1, err := version.Parse(s[i].Introduced)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
v2, err := version.Parse(s[j].Introduced)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return v1.LessThan(v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeVersionRange(affectedVersions []*Version) ([]*Version, error) {
|
||||||
|
// this special handling is made to handle to case of conceutive vulnable minor versions.
|
||||||
|
// example: vulnerable 1.3, 1.4, 1.5, 1.6 and prior to versions 1.7.14, 1.8.9 will be form as follow:
|
||||||
|
// Introduced: 1.3.0 Fixed: 1.7.14
|
||||||
|
// Introduced: 1.8.0 Fixed: 1.8.9
|
||||||
|
// example: https://cveawg.mitre.org/api/cve/CVE-2019-11249
|
||||||
|
sort.Sort(byVersion(affectedVersions))
|
||||||
|
newAffectedVesion := make([]*Version, 0)
|
||||||
|
minorVersions := make([]*Version, 0)
|
||||||
|
for _, av := range affectedVersions {
|
||||||
|
if minorVersion(av.Introduced) {
|
||||||
|
minorVersions = append(minorVersions, av)
|
||||||
|
} else if strings.Count(av.Introduced, ".") > 1 && len(minorVersions) > 0 {
|
||||||
|
newAffectedVesion = append(newAffectedVesion, &Version{
|
||||||
|
Introduced: fmt.Sprintf("%s.0", minorVersions[0].Introduced),
|
||||||
|
LastAffected: av.LastAffected,
|
||||||
|
Fixed: av.Fixed,
|
||||||
|
})
|
||||||
|
minorVersions = minorVersions[:0]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(minorVersions) == 0 {
|
||||||
|
newAffectedVesion = append(newAffectedVesion, av)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this special handling is made to handle to case of consecutive vulnable minor versions, wheen there is no fixed version is provided.
|
||||||
|
// example: vulnerable 1.3, 1.4, 1.5, 1.6 will be form as follow:
|
||||||
|
// Introduced: 1.3.0 Fixed: 1.7.0
|
||||||
|
if len(minorVersions) > 0 {
|
||||||
|
currentVersion := fmt.Sprintf("%s.0", minorVersions[len(minorVersions)-1].Introduced)
|
||||||
|
versionParts, err := versionParts(currentVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fixed := fmt.Sprintf("%d.%d.%d", versionParts[0], versionParts[1]+1, versionParts[2])
|
||||||
|
newAffectedVesion = append(newAffectedVesion, &Version{Introduced: fmt.Sprintf("%s.0", minorVersions[0].Introduced), Fixed: fixed})
|
||||||
|
}
|
||||||
|
return newAffectedVesion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMetrics(cve MitreCVE) (string, string) {
|
||||||
|
var vectorString string
|
||||||
|
var vectorType string
|
||||||
|
for _, metric := range cve.Containers.Cna.Metrics {
|
||||||
|
vectorString = metric.CvssV3_0.VectorString
|
||||||
|
vectorType = "CVSS_V3_0"
|
||||||
|
if len(vectorString) == 0 {
|
||||||
|
vectorString = metric.CvssV3_1.VectorString
|
||||||
|
vectorType = "CVSS_V3_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vectorString, vectorType
|
||||||
|
}
|
||||||
|
|
||||||
|
func versionParts(version string) ([]int, error) {
|
||||||
|
parts := strings.Split(version, ".")
|
||||||
|
intParts := make([]int, 0)
|
||||||
|
for _, p := range parts {
|
||||||
|
i, err := strconv.Atoi(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
intParts = append(intParts, i)
|
||||||
|
}
|
||||||
|
return intParts, nil
|
||||||
|
}
|
75
k8s/mitre_test.go
Normal file
75
k8s/mitre_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package k8s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSanitizedVersion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Name string
|
||||||
|
Version *MitreVersion
|
||||||
|
Want *MitreVersion
|
||||||
|
}{
|
||||||
|
{Name: "validate n/a version ", Version: &MitreVersion{Version: "n/a"}, Want: &MitreVersion{Version: "n/a"}},
|
||||||
|
{Name: "validate unspecified version ", Version: &MitreVersion{Version: "unspecified"}, Want: &MitreVersion{Version: "unspecified"}},
|
||||||
|
{Name: "validate less equal sign and version", Version: &MitreVersion{LessThanOrEqual: "<=", Version: "1.3.4"}, Want: &MitreVersion{Version: "1.3.4", LessThanOrEqual: "1.3.4"}},
|
||||||
|
{Name: "validate less sign in version", Version: &MitreVersion{Version: "< 1.3.4"}, Want: &MitreVersion{Version: "< 1.3.4", LessThan: "1.3.4"}},
|
||||||
|
{Name: "validate prior to then sign in version", Version: &MitreVersion{Version: "prior to 1.3.4"}, Want: &MitreVersion{Version: "prior to 1.3.4", LessThan: "1.3.4"}},
|
||||||
|
{Name: "validate prior to with minor in version", Version: &MitreVersion{Version: "prior to 1.3"}, Want: &MitreVersion{Version: "1.3.0", LessThan: "1.3.0"}},
|
||||||
|
{Name: "validate less with astrix", Version: &MitreVersion{LessThan: "1.3*"}, Want: &MitreVersion{Version: "1.3"}},
|
||||||
|
{Name: "validate less with x", Version: &MitreVersion{Version: "1.3.x"}, Want: &MitreVersion{Version: "1.3"}},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.Name, func(t *testing.T) {
|
||||||
|
got, _ := sanitizedVersions(tt.Version)
|
||||||
|
assert.Equal(t, got, tt.Want)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergedVersion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Name string
|
||||||
|
affectedVersions []*Version
|
||||||
|
WantAffectedVersions []*Version
|
||||||
|
}{
|
||||||
|
{Name: "merge regular version", affectedVersions: []*Version{
|
||||||
|
{Introduced: "1.2"},
|
||||||
|
{Introduced: "1.3"},
|
||||||
|
{Introduced: "1.4.1", LastAffected: "1.4.6"},
|
||||||
|
}, WantAffectedVersions: []*Version{
|
||||||
|
{Introduced: "1.2.0", LastAffected: "1.4.6"}},
|
||||||
|
},
|
||||||
|
{Name: "merge mixed version", affectedVersions: []*Version{
|
||||||
|
{Introduced: "1.3"},
|
||||||
|
{Introduced: "1.4"},
|
||||||
|
{Introduced: "1.5"},
|
||||||
|
{Introduced: "1.6"},
|
||||||
|
{Introduced: "1.7.0", Fixed: "1.7.14"},
|
||||||
|
{Introduced: "1.8.0", Fixed: "1.8.9"},
|
||||||
|
}, WantAffectedVersions: []*Version{
|
||||||
|
{Introduced: "1.3.0", Fixed: "1.7.14"},
|
||||||
|
{Introduced: "1.8.0", Fixed: "1.8.9"}},
|
||||||
|
},
|
||||||
|
{Name: "merge all minor version", affectedVersions: []*Version{
|
||||||
|
{Introduced: "1.3"},
|
||||||
|
{Introduced: "1.4"},
|
||||||
|
{Introduced: "1.5"},
|
||||||
|
{Introduced: "1.6"},
|
||||||
|
{Introduced: "1.7"},
|
||||||
|
}, WantAffectedVersions: []*Version{
|
||||||
|
{Introduced: "1.3.0", Fixed: "1.8.0"},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.Name, func(t *testing.T) {
|
||||||
|
gotLastAffected, err := mergeVersionRange(tt.affectedVersions)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, gotLastAffected, tt.WantAffectedVersions)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
140
k8s/parser.go
Normal file
140
k8s/parser.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package k8s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
version "github.com/aquasecurity/go-version/pkg/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UpstreamOrgName = map[string]string{
|
||||||
|
"k8s.io": "controller-manager,kubelet,apiserver,kubectl,kubernetes,kube-scheduler,kube-proxy",
|
||||||
|
"sigs.k8s.io": "secrets-store-csi-driver",
|
||||||
|
}
|
||||||
|
|
||||||
|
UpstreamRepoName = map[string]string{
|
||||||
|
"kube-controller-manager": "controller-manager",
|
||||||
|
"kubelet": "kubelet",
|
||||||
|
"kube-apiserver": "apiserver",
|
||||||
|
"kubectl": "kubectl",
|
||||||
|
"kubernetes": "kubernetes",
|
||||||
|
"kube-scheduler": "kube-scheduler",
|
||||||
|
"kube-proxy": "kube-proxy",
|
||||||
|
"api server": "apiserver",
|
||||||
|
"secrets-store-csi-driver": "secrets-store-csi-driver",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func trimString(s string, trimValues []string) string {
|
||||||
|
for _, v := range trimValues {
|
||||||
|
s = strings.Trim(s, v)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateVersions(to, introduce string) (string, string) {
|
||||||
|
// Example: https://cveawg.mitre.org/api/cve/CVE-2023-2878
|
||||||
|
if introduce == "0" {
|
||||||
|
return introduce, to
|
||||||
|
}
|
||||||
|
// Example: https://cveawg.mitre.org/api/cve/CVE-2019-11243
|
||||||
|
if minorVersion(introduce) {
|
||||||
|
return introduce + ".0", to
|
||||||
|
}
|
||||||
|
// Example: https://cveawg.mitre.org/api/cve/CVE-2019-1002100
|
||||||
|
if lIndex := strings.LastIndex(to, "."); lIndex != -1 {
|
||||||
|
return strings.TrimSpace(fmt.Sprintf("%s.%s", to[:lIndex], "0")), to
|
||||||
|
}
|
||||||
|
return introduce, to
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractRangeVersions(introduce string) (string, string) {
|
||||||
|
// Example https://cveawg.mitre.org/api/cve/CVE-2021-25749
|
||||||
|
var lastAffected string
|
||||||
|
validVersion := make([]string, 0)
|
||||||
|
// clean unwanted strings from versions
|
||||||
|
versionRangeParts := strings.Split(introduce, " ")
|
||||||
|
for _, p := range versionRangeParts {
|
||||||
|
candidate, err := version.Parse(p)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
validVersion = append(validVersion, candidate.String())
|
||||||
|
}
|
||||||
|
if len(validVersion) >= 1 {
|
||||||
|
introduce = strings.TrimSpace(validVersion[0])
|
||||||
|
}
|
||||||
|
if len(validVersion) == 2 {
|
||||||
|
lastAffected = strings.TrimSpace(validVersion[1])
|
||||||
|
}
|
||||||
|
return introduce, lastAffected
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMultiIDs(id string) []string {
|
||||||
|
var idsList []string
|
||||||
|
if strings.Contains(id, ",") {
|
||||||
|
idParts := strings.Split(id, ",")
|
||||||
|
for _, p := range idParts {
|
||||||
|
if strings.HasPrefix(strings.TrimSpace(p), "CVE-") {
|
||||||
|
idsList = append(idsList, strings.TrimSpace(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idsList
|
||||||
|
}
|
||||||
|
return []string{id}
|
||||||
|
}
|
||||||
|
|
||||||
|
func upstreamOrgByName(component string) string {
|
||||||
|
for key, components := range UpstreamOrgName {
|
||||||
|
for _, c := range strings.Split(components, ",") {
|
||||||
|
if strings.TrimSpace(c) == strings.ToLower(component) {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func upstreamRepoByName(component string) string {
|
||||||
|
if val, ok := UpstreamRepoName[component]; ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return component
|
||||||
|
}
|
||||||
|
|
||||||
|
func getComponentFromDescription(descriptions string, currentComponent string) string {
|
||||||
|
if strings.ToLower(currentComponent) != "kubernetes" {
|
||||||
|
return currentComponent
|
||||||
|
}
|
||||||
|
var compName string
|
||||||
|
var compCounter int
|
||||||
|
var kubeCtlVersionFound bool
|
||||||
|
CoreComponentsNaming := []string{"kube-controller-manager", "kubelet", "kube-apiserver", "kubectl", "kube-scheduler", "kube-proxy", "secrets-store-csi-driver", "api server"}
|
||||||
|
|
||||||
|
for _, key := range CoreComponentsNaming {
|
||||||
|
if strings.Contains(strings.ToLower(descriptions), key) {
|
||||||
|
c := strings.Count(strings.ToLower(descriptions), key)
|
||||||
|
if UpstreamRepoName[key] == compName {
|
||||||
|
compCounter = compCounter + c
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.ToLower(descriptions), "kubectl version") {
|
||||||
|
kubeCtlVersionFound = true
|
||||||
|
}
|
||||||
|
if c > compCounter {
|
||||||
|
compCounter = c
|
||||||
|
compName = UpstreamRepoName[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// in case found kubectl in env description and only one component found or no component found then fallback to k8s.io/kubernetes component
|
||||||
|
if len(compName) == 0 || (kubeCtlVersionFound && compName == "kubectl" && compCounter == 1) {
|
||||||
|
return currentComponent
|
||||||
|
}
|
||||||
|
return compName
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinorVersion returns true if version is minor version 1.1 or 2.2 and etc
|
||||||
|
func minorVersion(version string) bool {
|
||||||
|
return strings.Count(version, ".") == 1
|
||||||
|
}
|
47
k8s/parser_test.go
Normal file
47
k8s/parser_test.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package k8s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ExtractVersions(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
less string
|
||||||
|
wantIntroduce string
|
||||||
|
wantLastAffected string
|
||||||
|
}{
|
||||||
|
{name: "range less with minor", version: "1.2", less: "1.2.5", wantIntroduce: "1.2.0", wantLastAffected: "1.2.5"},
|
||||||
|
{name: "range less", version: "", less: "1.2.5", wantIntroduce: "1.2.0", wantLastAffected: "1.2.5"},
|
||||||
|
{name: "range lessThen", version: "", less: "1.2.5", wantIntroduce: "1.2.0", wantLastAffected: "1.2.5"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotIntoduce, gotLastAffected := updateVersions(tt.less, tt.version)
|
||||||
|
assert.Equal(t, gotIntoduce, tt.wantIntroduce)
|
||||||
|
assert.Equal(t, gotLastAffected, tt.wantLastAffected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ExtractRangeVersions(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
wantIntroduce string
|
||||||
|
wantLastAffected string
|
||||||
|
}{
|
||||||
|
{name: "range versions", version: "1.2.3 - 1.2.5", wantIntroduce: "1.2.3", wantLastAffected: "1.2.5"},
|
||||||
|
{name: "single versions", version: "1.2.5", wantIntroduce: "1.2.5", wantLastAffected: ""},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotIntoduce, gotLastAffected := extractRangeVersions(tt.version)
|
||||||
|
assert.Equal(t, gotIntoduce, tt.wantIntroduce)
|
||||||
|
assert.Equal(t, gotLastAffected, tt.wantLastAffected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
1
k8s/testdata/expected-vulndb.json
vendored
Normal file
1
k8s/testdata/expected-vulndb.json
vendored
Normal file
File diff suppressed because one or more lines are too long
91
k8s/testdata/happy/upstream/CVE-2018-1002102
vendored
Normal file
91
k8s/testdata/happy/upstream/CVE-2018-1002102
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"id": "CVE-2018-1002102",
|
||||||
|
"modified": "2018-11-26T11:07:36Z",
|
||||||
|
"published": "2018-11-26T11:07:36Z",
|
||||||
|
"summary": "proxy request handling in kube-apiserver can leave vulnerable TCP connections",
|
||||||
|
"details": "In all Kubernetes versions prior to v1.10.11, v1.11.5, and v1.12.3, incorrect handling of error responses to proxied upgrade requests in the kube-apiserver
|
||||||
|
allowed specially crafted requests to establish a connection through the Kubernetes API server to backend servers, then send arbitrary requests over the same connection
|
||||||
|
directly to the backend, authenticated with the Kubernetes API server's TLS credentials used to establish the backend connection.",
|
||||||
|
"affected": [
|
||||||
|
{
|
||||||
|
"package": {
|
||||||
|
"ecosystem": "kubernetes",
|
||||||
|
"name": "k8s.io/apiserver"
|
||||||
|
},
|
||||||
|
"severity": [
|
||||||
|
{
|
||||||
|
"type": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"score": "9.8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"introduced": "1.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fixed": "1.10.11"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package": {
|
||||||
|
"ecosystem": "kubernetes",
|
||||||
|
"name": "k8s.io/apiserver"
|
||||||
|
},
|
||||||
|
"severity": [
|
||||||
|
{
|
||||||
|
"type": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"score": "9.8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"introduced": "1.11.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fixed": "1.11.5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package": {
|
||||||
|
"ecosystem": "kubernetes",
|
||||||
|
"name": "k8s.io/apiserver"
|
||||||
|
},
|
||||||
|
"severity": [
|
||||||
|
{
|
||||||
|
"type": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"score": "9.8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"introduced": "1.12.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fixed": "1.12.3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/kubernetes/kubernetes/issues/71411"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.cve.org/cverecord?id=CVE-2018-1002105"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
535
k8s/testdata/k8s-db.json
vendored
Normal file
535
k8s/testdata/k8s-db.json
vendored
Normal file
File diff suppressed because one or more lines are too long
7
main.go
7
main.go
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/aquasecurity/vuln-list-update/debian/tracker"
|
"github.com/aquasecurity/vuln-list-update/debian/tracker"
|
||||||
"github.com/aquasecurity/vuln-list-update/ghsa"
|
"github.com/aquasecurity/vuln-list-update/ghsa"
|
||||||
"github.com/aquasecurity/vuln-list-update/glad"
|
"github.com/aquasecurity/vuln-list-update/glad"
|
||||||
|
"github.com/aquasecurity/vuln-list-update/k8s"
|
||||||
"github.com/aquasecurity/vuln-list-update/kevc"
|
"github.com/aquasecurity/vuln-list-update/kevc"
|
||||||
"github.com/aquasecurity/vuln-list-update/mariner"
|
"github.com/aquasecurity/vuln-list-update/mariner"
|
||||||
"github.com/aquasecurity/vuln-list-update/nvd"
|
"github.com/aquasecurity/vuln-list-update/nvd"
|
||||||
@ -38,7 +39,7 @@ import (
|
|||||||
|
|
||||||
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, ubuntu, amazon, oracle-oval, suse-cvrf, photon, arch-linux, ghsa, glad, cwe, osv, mariner, kevc, wolfi, chainguard)")
|
"debian, ubuntu, amazon, oracle-oval, suse-cvrf, photon, arch-linux, ghsa, glad, cwe, osv, mariner, kevc, wolfi, chainguard, k8s)")
|
||||||
vulnListDir = flag.String("vuln-list-dir", "", "vuln-list dir")
|
vulnListDir = flag.String("vuln-list-dir", "", "vuln-list dir")
|
||||||
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)")
|
||||||
@ -171,6 +172,10 @@ func run() error {
|
|||||||
if err := cu.Update(); err != nil {
|
if err := cu.Update(); err != nil {
|
||||||
return xerrors.Errorf("Chainguard update error: %w", err)
|
return xerrors.Errorf("Chainguard update error: %w", err)
|
||||||
}
|
}
|
||||||
|
case "k8s":
|
||||||
|
if err := k8s.Update(); err != nil {
|
||||||
|
return xerrors.Errorf("Chainguard update error: %w", err)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return xerrors.New("unknown target")
|
return xerrors.New("unknown target")
|
||||||
}
|
}
|
||||||
|
17
osv/types.go
17
osv/types.go
@ -1,13 +1,20 @@
|
|||||||
package osv
|
package osv
|
||||||
|
|
||||||
type Affected struct {
|
type Affected struct {
|
||||||
Package Package `json:"package,omitempty"`
|
Package Package `json:"package,omitempty"`
|
||||||
Ranges []Range `json:"ranges,omitempty"`
|
Severities []Severity `json:"severity,omitempty"`
|
||||||
Versions []string `json:"versions,omitempty"`
|
Ranges []Range `json:"ranges,omitempty"`
|
||||||
Ecosystem interface{} `json:"ecosystem_specific,omitempty"` //The meaning of the values within the object is entirely defined by the ecosystem
|
Versions []string `json:"versions,omitempty"`
|
||||||
Database interface{} `json:"database_specific,omitempty"` //The meaning of the values within the object is entirely defined by the database
|
Ecosystem interface{} `json:"ecosystem_specific,omitempty"` //The meaning of the values within the object is entirely defined by the ecosystem
|
||||||
|
Database interface{} `json:"database_specific,omitempty"` //The meaning of the values within the object is entirely defined by the database
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Severity struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Score string `json:"score"`
|
||||||
|
}
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
Ecosystem string `json:"ecosystem,omitempty"`
|
Ecosystem string `json:"ecosystem,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
Loading…
Reference in New Issue
Block a user