├── .binny.yaml ├── .bouncer.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── actions │ └── bootstrap │ │ └── action.yaml ├── dependabot.yml ├── scripts │ ├── aggregate-all-provider-cache.py │ ├── ci-check.sh │ ├── coverage.py │ ├── go-mod-tidy-check.sh │ └── trigger-release.sh └── workflows │ ├── copy-listing-from-r2.yaml │ ├── daily-data-sync.yaml │ ├── daily-db-publisher-r2.yaml │ ├── dependabot-automation.yaml │ ├── oss-project-board-add.yaml │ ├── release.yaml │ ├── remove-awaiting-response-label.yaml │ ├── staging-db-publisher.yaml │ ├── update-anchore-dependencies.yml │ ├── update-bootstrap-tools.yml │ ├── update-generated-code.yaml │ └── validations.yaml ├── .gitignore ├── .gitmodules ├── .golangci.yaml ├── .goreleaser.yaml ├── .grype-db-manager.yaml ├── .vunnel.yaml ├── .yardstick.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPING.md ├── LICENSE ├── Makefile ├── README.md ├── RELEASE.md ├── bump-schema.py ├── cmd └── grype-db │ ├── application │ ├── application.go │ ├── build_info.go │ ├── cache.go │ ├── config.go │ ├── development.go │ └── logging.go │ ├── cli │ ├── cli.go │ ├── commands │ │ ├── build.go │ │ ├── cache.go │ │ ├── cache_backup.go │ │ ├── cache_backup_test.go │ │ ├── cache_delete.go │ │ ├── cache_restore.go │ │ ├── cache_restore_test.go │ │ ├── cache_status.go │ │ ├── cache_status_test.go │ │ ├── list_providers.go │ │ ├── package.go │ │ ├── pull.go │ │ ├── root.go │ │ ├── test-fixtures │ │ │ └── test-root │ │ │ │ └── test-provider │ │ │ │ ├── input │ │ │ │ └── some-input-file.txt │ │ │ │ ├── metadata.json │ │ │ │ └── results │ │ │ │ └── results.db │ │ ├── utils.go │ │ └── version.go │ └── options │ │ ├── build.go │ │ ├── cache_archive.go │ │ ├── cache_restore.go │ │ ├── db_location.go │ │ ├── format.go │ │ ├── options.go │ │ ├── package.go │ │ ├── provider.go │ │ ├── provider_selection.go │ │ ├── pull.go │ │ ├── results.go │ │ ├── store.go │ │ ├── utils.go │ │ └── vunnel.go │ └── main.go ├── config ├── grype-db-manager │ ├── acceptance-pr.yaml │ ├── include.d │ │ ├── data.yaml │ │ ├── distribution-production-r2.yaml │ │ ├── distribution-production.yaml │ │ ├── distribution-staging.yaml │ │ ├── grype-db-local-build-r2.yaml │ │ ├── grype-db-local-build.yaml │ │ └── validate.yaml │ ├── publish-production-r2.yaml │ ├── publish-production.yaml │ └── publish-staging.yaml └── grype-db │ ├── publish-nightly-r2.yaml │ └── publish-nightly.yaml ├── data └── yardstick │ └── labels ├── go.mod ├── go.sum ├── install.sh ├── internal ├── bus │ └── bus.go ├── constants.go ├── eventloop │ ├── eventloop.go │ └── eventloop_test.go ├── file │ ├── exists.go │ ├── getter.go │ └── hasher.go ├── format │ ├── color.go │ └── tprint.go ├── log │ ├── log.go │ └── redactable.go ├── stringset.go ├── tarutil │ ├── file_entry.go │ ├── file_entry_test.go │ ├── populate.go │ ├── populate_test.go │ ├── reader_entry.go │ ├── reader_entry_test.go │ ├── tar.go │ ├── writer.go │ └── writer_test.go ├── ui │ ├── config.go │ ├── loggerui │ │ └── ui.go │ ├── select.go │ └── ui.go └── utils │ └── indent.go ├── manager ├── .coveragerc ├── Makefile ├── README.md ├── __init__.py ├── src │ └── grype_db_manager │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── cli │ │ ├── __init__.py │ │ ├── cli.py │ │ ├── config.py │ │ ├── db.py │ │ ├── error.py │ │ ├── listing.py │ │ └── tool.py │ │ ├── data │ │ └── schema-info.json │ │ ├── db │ │ ├── __init__.py │ │ ├── format.py │ │ ├── latest.py │ │ ├── listing.py │ │ ├── metadata.py │ │ ├── schema.py │ │ └── validation.py │ │ ├── distribution.py │ │ ├── grype.py │ │ ├── grypedb.py │ │ ├── s3utils.py │ │ └── utils.py └── tests │ ├── __init__.py │ ├── cli │ ├── .gitignore │ ├── .grype-db-manager.yaml │ ├── .grype-db.yaml │ ├── .vunnel.yaml │ ├── .yardstick.yaml │ ├── Makefile │ ├── README.md │ ├── conftest.py │ ├── s3-mock │ │ ├── .gitignore │ │ ├── .grype-db-manager.yaml │ │ ├── docker-compose.yaml │ │ ├── setup-legacy-workflow-3.py │ │ ├── setup-legacy-workflow-4.py │ │ └── setup-workflow-1.py │ ├── test_legacy_workflows.py │ └── test_workflows.py │ ├── conftest.py │ ├── fixtures │ ├── dbs-case-1 │ │ ├── .gitignore │ │ ├── README.md │ │ └── dbs │ │ │ ├── 41e4c9e7-73c7-4106-bfb3-82e58ce15d9a │ │ │ ├── build │ │ │ │ ├── listing.json │ │ │ │ └── metadata.json │ │ │ ├── stage │ │ │ │ └── vulnerability-db_v5_2023-08-03T01:34:34Z_54b7b6a76b058f1fa587.tar.gz │ │ │ └── timestamp │ │ │ └── 9d1fce98-9c10-4887-949e-8296a259daf5 │ │ │ ├── build │ │ │ ├── listing.json │ │ │ └── metadata.json │ │ │ ├── stage │ │ │ └── vulnerability-db_v4_2023-08-03T01:34:34Z_54b7b6a76b058f1fa587.tar.gz │ │ │ └── timestamp │ ├── tools-case-1 │ │ └── tools │ │ │ └── grype-db │ │ │ └── bin │ │ │ ├── grype-db-v0.18.0 │ │ │ ├── grype-db-v0.19.0 │ │ │ └── grype-db-v0.19.0-2-gda1ca9e-dirty │ └── yardstick-sbom-result-set │ │ ├── effect │ │ └── docker.io+ubuntu@sha256:aa6c2c047467afc828e77e306041b7fa4a65734fe3449a54aa9c280822b0d87d │ │ │ └── syft@v0.74.1 │ │ │ └── 2023-06-30T12:57:59.354289+00:00 │ │ │ ├── data.json │ │ │ └── metadata.json │ │ └── result │ │ └── sets │ │ └── test-set.json │ └── unit │ ├── __init__.py │ ├── cli │ ├── __init__.py │ ├── fixtures │ │ ├── config │ │ │ └── full.yaml │ │ ├── db │ │ │ └── upload-test-config.yaml │ │ └── listing │ │ │ ├── create-all-exists │ │ │ ├── .grype-db-manager.yaml │ │ │ ├── expected-listing.json │ │ │ └── input-listing.json │ │ │ └── create-new-db │ │ │ ├── .grype-db-manager.yaml │ │ │ ├── expected-listing.json │ │ │ └── input-listing.json │ ├── test_config.py │ ├── test_db.py │ └── test_listing.py │ ├── db │ ├── __init__.py │ ├── fixtures │ │ ├── result-set-stale-detection │ │ │ ├── different-image-set │ │ │ │ └── result │ │ │ │ │ └── sets │ │ │ │ │ └── result-set.json │ │ │ ├── good │ │ │ │ └── result │ │ │ │ │ └── sets │ │ │ │ │ └── result-set.json │ │ │ ├── inconsistent-db-checksum │ │ │ │ └── result │ │ │ │ │ └── sets │ │ │ │ │ └── result-set.json │ │ │ ├── missing-grype-request │ │ │ │ └── result │ │ │ │ │ └── sets │ │ │ │ │ └── result-set.json │ │ │ ├── missing-result-set │ │ │ │ └── result │ │ │ │ │ └── sets │ │ │ │ │ └── missing │ │ │ └── unfulfilled-request │ │ │ │ └── result │ │ │ │ └── sets │ │ │ │ └── result-set.json │ │ └── validate-image │ │ │ ├── .yardstick.yaml │ │ │ ├── label-sets │ │ │ ├── all-tp │ │ │ │ └── labels │ │ │ │ │ └── docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495 │ │ │ │ │ ├── 0e288c90-f8e5-4a9d-a768-d04d9876b831.json │ │ │ │ │ ├── 1cfae55e-4f8a-4d1e-b2ff-6ce962096299.json │ │ │ │ │ ├── 2e30c6cd-cfcb-4fec-abfe-36cea35465cb.json │ │ │ │ │ ├── 51332abc-47d5-4751-8776-ce69367b7201.json │ │ │ │ │ ├── 5ce7cadb-9c1b-4766-88d0-3a710544bc66.json │ │ │ │ │ ├── 726baa17-77da-49b9-857a-41cfc8474f94.json │ │ │ │ │ ├── 764afea8-909c-4cc1-a582-5f19eea73468.json │ │ │ │ │ ├── 78318f73-ee3c-4956-be18-57a2cbb9fc10.json │ │ │ │ │ ├── 7bd80a83-13ae-407c-805c-678e21ce993b.json │ │ │ │ │ ├── 89ebd842-6a70-4e64-b3a4-5243fd938dc4.json │ │ │ │ │ ├── 91248621-e9ab-4372-9776-1fcccf40d177.json │ │ │ │ │ ├── 9dad5945-f6bc-4294-8248-96e1c841edfe.json │ │ │ │ │ ├── 9e3fbee0-fde6-49ab-8d93-9848f4f266dc.json │ │ │ │ │ ├── b48e76c0-3619-490e-b601-59782d3c7c4e.json │ │ │ │ │ ├── ba20833c-8a08-49e2-8fb5-db7ac3398cb3.json │ │ │ │ │ ├── bb261f04-d5f8-4db1-937f-97db94879355.json │ │ │ │ │ ├── be8c414f-0ddc-4a4f-9e79-91923d3852c1.json │ │ │ │ │ ├── cf5f84ad-9c80-48b0-be89-7d74f0f7d8dd.json │ │ │ │ │ ├── dd572e83-d184-4c2b-96b4-8d7ce32bfc6d.json │ │ │ │ │ ├── ed124564-6e4d-4589-8c3d-638ce467a999.json │ │ │ │ │ └── f0351994-014f-4140-a9a7-11d37998d66a.json │ │ │ └── first-half-fp │ │ │ │ └── labels │ │ │ │ └── docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495 │ │ │ │ ├── 06bbb581-5f08-401c-9154-aebdbdb93888.json │ │ │ │ ├── 0bf6b52b-0445-45a4-883a-033aa7ba30c3.json │ │ │ │ ├── 0f778a6f-a14e-4535-9338-15eb5bf608ac.json │ │ │ │ ├── 1a93ca64-31a9-48f7-b87b-33fef666c479.json │ │ │ │ ├── 3875af9b-c820-444c-bdc4-26279badb612.json │ │ │ │ ├── 3aeed8ef-eac4-44d0-a127-dbc5b9648c4d.json │ │ │ │ ├── 48331d83-15cf-498b-8287-c8b93236088d.json │ │ │ │ ├── 4fcfaa8e-f98c-4269-a78f-8c0e4c159c3c.json │ │ │ │ ├── 5f997560-e5fc-4a0f-873b-1880355b6ebe.json │ │ │ │ ├── 6f5baf1a-858d-40b4-acab-b934bef7119d.json │ │ │ │ ├── 72e78828-082b-4ca3-b903-8879b15cc54d.json │ │ │ │ ├── 76189aae-a342-4612-91d2-5375b2c0767d.json │ │ │ │ ├── 8f983ee0-c97c-477d-b5c8-2a463c447aaf.json │ │ │ │ ├── a43a29b7-c2a9-41de-af13-27c7935f79b5.json │ │ │ │ ├── bd2a4f1f-3e18-4bd6-b0b5-591e3331ca61.json │ │ │ │ ├── d3f3ed73-6439-4b17-b65e-c45097465a9f.json │ │ │ │ ├── d92ba7d3-3784-4908-8e97-61762388e0ee.json │ │ │ │ ├── dfcc3309-8832-4bc0-aa25-66c9af24b1fd.json │ │ │ │ ├── e5706ac8-e06d-46f8-a04f-32843ee56483.json │ │ │ │ ├── e901d5b8-9462-45c2-8c0d-04a606425ddb.json │ │ │ │ └── f9495fc7-4e78-4923-85e6-048620ae460b.json │ │ │ └── yardstick │ │ │ ├── .gitignore │ │ │ └── result │ │ │ ├── sets │ │ │ ├── go-case.json │ │ │ ├── new-db-run-missing-half.json │ │ │ └── old-db-run-missing-half.json │ │ │ └── store │ │ │ └── docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495 │ │ │ ├── grype@v0.65.1 │ │ │ ├── 2023-01-01T01:01:01.000001+00:00 │ │ │ │ ├── data.json │ │ │ │ └── metadata.json │ │ │ ├── 2023-01-01T02:02:02.000002+00:00 │ │ │ │ ├── data.json │ │ │ │ └── metadata.json │ │ │ └── 2023-01-01T03:03:03.000003+00:00 │ │ │ │ ├── data.json │ │ │ │ └── metadata.json │ │ │ └── grype[custom-db]@v0.65.1 │ │ │ ├── 2023-02-02T01:01:01.000001+00:00 │ │ │ ├── data.json │ │ │ └── metadata.json │ │ │ ├── 2023-02-02T02:02:02.000002+00:00 │ │ │ ├── data.json │ │ │ └── metadata.json │ │ │ └── 2023-02-02T03:03:03.000003+00:00 │ │ │ ├── data.json │ │ │ └── metadata.json │ ├── test_listing.py │ ├── test_metadata.py │ ├── test_schema.py │ └── test_validation.py │ ├── fixtures │ └── hash │ │ └── target │ ├── test_distribution.py │ └── test_grypedb.py ├── pkg ├── data │ ├── entry.go │ ├── processor.go │ ├── severity.go │ ├── severity_test.go │ ├── transformers.go │ └── writer.go ├── event │ └── event.go ├── lib.go ├── process │ ├── build.go │ ├── default_schema_version.go │ ├── generate.go │ ├── internal │ │ ├── codename │ │ │ ├── codename.go │ │ │ ├── codename_test.go │ │ │ ├── codenames_generated.go │ │ │ └── generate │ │ │ │ └── main.go │ │ ├── common │ │ │ ├── clean_fixed_in_version.go │ │ │ ├── constraint.go │ │ │ └── constraint_test.go │ │ └── tests │ │ │ └── utils.go │ ├── package.go │ ├── package_legacy.go │ ├── processors │ │ ├── epss_processor.go │ │ ├── epss_processor_test.go │ │ ├── github_processor.go │ │ ├── github_processor_test.go │ │ ├── kev_processor.go │ │ ├── kev_processor_test.go │ │ ├── match_exclusion_processor.go │ │ ├── match_exclusion_processor_test.go │ │ ├── msrc_processor.go │ │ ├── msrc_processor_test.go │ │ ├── nvd_processor.go │ │ ├── nvd_processor_test.go │ │ ├── os_processor.go │ │ ├── os_processor_test.go │ │ ├── osv_processor.go │ │ ├── osv_processor_test.go │ │ ├── test-fixtures │ │ │ ├── epss.json │ │ │ ├── exclusions.json │ │ │ ├── github.json │ │ │ ├── kev.json │ │ │ ├── msrc.json │ │ │ ├── nvd.json │ │ │ ├── oracle.json │ │ │ ├── os.json │ │ │ └── osv.json │ │ ├── version.go │ │ └── version_test.go │ ├── pull.go │ ├── v5 │ │ ├── processors.go │ │ ├── transformers │ │ │ ├── entry.go │ │ │ ├── github │ │ │ │ ├── test-fixtures │ │ │ │ │ ├── github-github-npm-0.json │ │ │ │ │ ├── github-github-python-0.json │ │ │ │ │ ├── github-github-python-1.json │ │ │ │ │ ├── github-withdrawn.json │ │ │ │ │ └── multiple-fixed-in-names.json │ │ │ │ ├── transform.go │ │ │ │ └── transform_test.go │ │ │ ├── matchexclusions │ │ │ │ └── transform.go │ │ │ ├── msrc │ │ │ │ ├── test-fixtures │ │ │ │ │ └── microsoft-msrc-0.json │ │ │ │ ├── transform.go │ │ │ │ └── transform_test.go │ │ │ ├── nvd │ │ │ │ ├── test-fixtures │ │ │ │ │ ├── CVE-2023-45283-platform-cpe-first.json │ │ │ │ │ ├── CVE-2023-45283-platform-cpe-last.json │ │ │ │ │ ├── compound-pkg.json │ │ │ │ │ ├── cve-2020-10729.json │ │ │ │ │ ├── cve-2022-0543.json │ │ │ │ │ ├── invalid_cpe.json │ │ │ │ │ ├── multiple-platforms-with-application-cpe.json │ │ │ │ │ ├── platform-cpe.json │ │ │ │ │ ├── single-package-multi-distro.json │ │ │ │ │ ├── unmarshal-test.json │ │ │ │ │ └── version-range.json │ │ │ │ ├── transform.go │ │ │ │ ├── transform_test.go │ │ │ │ ├── unique_pkg.go │ │ │ │ ├── unique_pkg_test.go │ │ │ │ └── unique_pkg_tracker.go │ │ │ ├── os │ │ │ │ ├── test-fixtures │ │ │ │ │ ├── alpine-3.9.json │ │ │ │ │ ├── amazon-multiple-kernel-advisories.json │ │ │ │ │ ├── amzn.json │ │ │ │ │ ├── azure-linux-3.json │ │ │ │ │ ├── debian-8-multiple-entries-for-same-package.json │ │ │ │ │ ├── debian-8.json │ │ │ │ │ ├── mariner-20.json │ │ │ │ │ ├── mariner-range.json │ │ │ │ │ ├── ol-8-modules.json │ │ │ │ │ ├── ol-8.json │ │ │ │ │ ├── rhel-8-modules.json │ │ │ │ │ ├── rhel-8.json │ │ │ │ │ └── unmarshal-test.json │ │ │ │ ├── transform.go │ │ │ │ └── transform_test.go │ │ │ └── vulnerability_metadata.go │ │ ├── writer.go │ │ └── writer_test.go │ └── v6 │ │ ├── archive.go │ │ ├── internal │ │ └── tests │ │ │ └── utils.go │ │ ├── processors.go │ │ ├── transformers │ │ ├── entry.go │ │ ├── epss │ │ │ ├── test-fixtures │ │ │ │ └── go-case.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ ├── github │ │ │ ├── test-fixtures │ │ │ │ ├── GHSA-2wgc-48g2-cj5w.json │ │ │ │ ├── GHSA-3x74-v64j-qc3f.json │ │ │ │ ├── GHSA-92cp-5422-2mw7.json │ │ │ │ ├── github-github-npm-0.json │ │ │ │ ├── github-github-python-0.json │ │ │ │ ├── github-withdrawn.json │ │ │ │ └── multiple-fixed-in-names.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ ├── internal │ │ │ ├── provider.go │ │ │ ├── provider_test.go │ │ │ ├── sort.go │ │ │ ├── time.go │ │ │ └── time_test.go │ │ ├── kev │ │ │ ├── test-fixtures │ │ │ │ └── go-case.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ ├── msrc │ │ │ ├── test-fixtures │ │ │ │ └── microsoft-msrc-0.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ ├── nvd │ │ │ ├── affected_range.go │ │ │ ├── affected_range_test.go │ │ │ ├── node.go │ │ │ ├── node_test.go │ │ │ ├── test-fixtures │ │ │ │ ├── CVE-2008-3442.json │ │ │ │ ├── CVE-2023-45283-platform-cpe-first.json │ │ │ │ ├── CVE-2023-45283-platform-cpe-last.json │ │ │ │ ├── compound-pkg.json │ │ │ │ ├── cve-2020-10729.json │ │ │ │ ├── cve-2021-1566.json │ │ │ │ ├── cve-2022-0543.json │ │ │ │ ├── cve-2024-26663-standalone-os.json │ │ │ │ ├── invalid_cpe.json │ │ │ │ ├── multiple-platforms-with-application-cpe.json │ │ │ │ ├── platform-cpe.json │ │ │ │ ├── single-package-multi-distro.json │ │ │ │ └── version-range.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ ├── os │ │ │ ├── test-fixtures │ │ │ │ ├── alpine-3.9.json │ │ │ │ ├── amazon-multiple-kernel-advisories.json │ │ │ │ ├── amzn.json │ │ │ │ ├── azure-linux-3.json │ │ │ │ ├── debian-8-multiple-entries-for-same-package.json │ │ │ │ ├── debian-8.json │ │ │ │ ├── mariner-20.json │ │ │ │ ├── mariner-range.json │ │ │ │ ├── ol-8-modules.json │ │ │ │ ├── ol-8.json │ │ │ │ ├── rhel-8-modules.json │ │ │ │ └── rhel-8.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ └── osv │ │ │ ├── test-fixtures │ │ │ ├── BIT-apache-2020-11984.json │ │ │ └── BIT-node-2020-8201.json │ │ │ ├── transform.go │ │ │ └── transform_test.go │ │ ├── writer.go │ │ └── writer_test.go └── provider │ ├── config.go │ ├── entry │ ├── file.go │ ├── opener.go │ └── sqlite.go │ ├── file.go │ ├── provider.go │ ├── providers │ ├── external │ │ ├── log_writer.go │ │ ├── log_writer_test.go │ │ └── provider.go │ ├── providers.go │ └── vunnel │ │ └── provider.go │ ├── state.go │ ├── state_test.go │ ├── unmarshal │ ├── epss.go │ ├── errors.go │ ├── github_advisory.go │ ├── items_envelope.go │ ├── known_exploited_vulnerability.go │ ├── match_exclusion.go │ ├── msrc_vulnerability.go │ ├── nvd │ │ ├── cve.go │ │ ├── cve_test.go │ │ ├── cvss20 │ │ │ └── cvss20.go │ │ ├── cvss30 │ │ │ └── cvss30.go │ │ ├── cvss31 │ │ │ └── cvss31.go │ │ └── cvss40 │ │ │ └── cvss40.go │ ├── nvd_vulnerability.go │ ├── os_vulnerability.go │ ├── os_vulnerability_test.go │ ├── osv_vulnerability.go │ └── single_or_multi.go │ └── workspace.go ├── pyproject.toml ├── test ├── cli │ ├── log_redaction_test.go │ ├── test-fixtures │ │ └── grype-db-config-with-secrets.yaml │ ├── trait_assertion_test.go │ └── utils_test.go └── db │ └── acceptance.sh └── uv.lock /.bouncer.yaml: -------------------------------------------------------------------------------- 1 | permit: 2 | - BSD.* 3 | - MIT.* 4 | - Apache.* 5 | - MPL.* 6 | - ISC 7 | - CC0-1.0 8 | ignore-packages: 9 | # packageurl-go is released under the MIT license located in the root of the repo at /mit.LICENSE 10 | - github.com/anchore/packageurl-go 11 | 12 | # tools-golang is released under the Apache License, version 2.0 (Apache-2.0) 13 | # https://github.com/spdx/tools-golang/blob/main/LICENSE.code 14 | - github.com/spdx/tools-golang 15 | 16 | # from: https://github.com/xi2/xz/blob/master/LICENSE 17 | # All these files have been put into the public domain. 18 | # You can do whatever you want with these files. 19 | - github.com/xi2/xz 20 | 21 | # from: https://gitlab.com/cznic/sqlite/-/blob/v1.15.4/LICENSE 22 | # This is a BSD-3-Clause license 23 | - modernc.org/libc 24 | - modernc.org/libc/errno 25 | - modernc.org/libc/fcntl 26 | - modernc.org/libc/fts 27 | - modernc.org/libc/grp 28 | - modernc.org/libc/langinfo 29 | - modernc.org/libc/limits 30 | - modernc.org/libc/netdb 31 | - modernc.org/libc/netinet/in 32 | - modernc.org/libc/poll 33 | - modernc.org/libc/pthread 34 | - modernc.org/libc/pwd 35 | - modernc.org/libc/signal 36 | - modernc.org/libc/stdio 37 | - modernc.org/libc/stdlib 38 | - modernc.org/libc/sys/socket 39 | - modernc.org/libc/sys/stat 40 | - modernc.org/libc/sys/types 41 | - modernc.org/libc/termios 42 | - modernc.org/libc/time 43 | - modernc.org/libc/unistd 44 | - modernc.org/libc/utime 45 | - modernc.org/libc/uuid/uuid 46 | - modernc.org/libc/wctype 47 | - modernc.org/mathutil 48 | - modernc.org/memory 49 | 50 | # from: https://pkg.go.dev/crypto/internal/boring?tab=licenses 51 | # This is a BSD-3-Clause, ISC, and OpenSSL style license 52 | - crypto/internal/boring 53 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Please provide a set of steps on how to reproduce the issue** 11 | 12 | **What happened**: 13 | 14 | **What you expected to happen**: 15 | 16 | **Anything else we need to know?**: 17 | 18 | **Environment**: 19 | - Output of `grype-db version`: 20 | - OS (e.g: `cat /etc/os-release` or similar): 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | 3 | - name: Join our Discourse community 💬 4 | # link to our community Discourse site 5 | url: https://anchore.com/discourse 6 | about: 'Come chat with us! Ask for help, join our software development efforts, or just give us feedback!' 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What would you like to be added**: 11 | 12 | **Why is this needed**: 13 | 14 | **Additional context**: 15 | 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | open-pull-requests-limit: 10 8 | labels: 9 | - "dependencies" 10 | 11 | - package-ecosystem: "github-actions" 12 | directory: "/" 13 | schedule: 14 | interval: "daily" 15 | open-pull-requests-limit: 10 16 | labels: 17 | - "dependencies" 18 | 19 | - package-ecosystem: "github-actions" 20 | directory: "/.github/actions/bootstrap" 21 | schedule: 22 | interval: "daily" 23 | open-pull-requests-limit: 10 24 | labels: 25 | - "dependencies" -------------------------------------------------------------------------------- /.github/scripts/aggregate-all-provider-cache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import ast 4 | import sys 5 | import subprocess 6 | 7 | output = os.environ.get("PROVIDERS_USED", None) 8 | 9 | if not output: 10 | print(f"invoking grype-db to get list of providers to use") 11 | output = subprocess.run("make show-providers", shell=True, check=True, stdout=subprocess.PIPE, stderr=sys.stderr).stdout 12 | else: 13 | print("using values from $PROVIDERS_USED environment variable") 14 | 15 | print(f"output: {output!r}") 16 | 17 | # why in the world would we use ast instead of JSON?! 18 | # short answer: python borks when there are strings with single quotes instead of double quotes 19 | providers = ast.literal_eval(output) 20 | 21 | print(f"providers: {providers}") 22 | 23 | for provider in providers: 24 | subprocess.run(f"make download-provider-cache provider={provider}", shell=True, check=True, stdout=sys.stdout, stderr=sys.stderr) 25 | -------------------------------------------------------------------------------- /.github/scripts/ci-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | red=$(tput setaf 1) 4 | bold=$(tput bold) 5 | normal=$(tput sgr0) 6 | 7 | # assert we are running in CI (or die!) 8 | if [[ -z "$CI" ]]; then 9 | echo "${bold}${red}This script should ONLY be run in CI. Exiting...${normal}" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /.github/scripts/coverage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import subprocess 3 | import sys 4 | import shlex 5 | 6 | 7 | class bcolors: 8 | HEADER = '\033[95m' 9 | OKBLUE = '\033[94m' 10 | OKCYAN = '\033[96m' 11 | OKGREEN = '\033[92m' 12 | WARNING = '\033[93m' 13 | FAIL = '\033[91m' 14 | ENDC = '\033[0m' 15 | BOLD = '\033[1m' 16 | UNDERLINE = '\033[4m' 17 | 18 | 19 | if len(sys.argv) < 3: 20 | print("Usage: coverage.py [threshold] [go-coverage-report]") 21 | sys.exit(1) 22 | 23 | 24 | threshold = float(sys.argv[1]) 25 | report = sys.argv[2] 26 | 27 | 28 | args = shlex.split(f"go tool cover -func {report}") 29 | p = subprocess.run(args, capture_output=True, text=True) 30 | 31 | percent_coverage = float(p.stdout.splitlines()[-1].split()[-1].replace("%", "")) 32 | print(f"{bcolors.BOLD}Coverage: {percent_coverage}%{bcolors.ENDC}") 33 | 34 | if percent_coverage < threshold: 35 | print(f"{bcolors.BOLD}{bcolors.FAIL}Coverage below threshold of {threshold}%{bcolors.ENDC}") 36 | sys.exit(1) 37 | -------------------------------------------------------------------------------- /.github/scripts/go-mod-tidy-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | ORIGINAL_STATE_DIR=$(mktemp -d "TEMP-original-state-XXXXXXXXX") 5 | TIDY_STATE_DIR=$(mktemp -d "TEMP-tidy-state-XXXXXXXXX") 6 | 7 | trap "cp -p ${ORIGINAL_STATE_DIR}/* ./ && git update-index -q --refresh && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT 8 | 9 | # capturing original state of files... 10 | cp go.mod go.sum "${ORIGINAL_STATE_DIR}" 11 | 12 | # capturing state of go.mod and go.sum after running go mod tidy... 13 | go mod tidy 14 | cp go.mod go.sum "${TIDY_STATE_DIR}" 15 | 16 | set +e 17 | 18 | # detect difference between the git HEAD state and the go mod tidy state 19 | DIFF_MOD=$(diff -u "${ORIGINAL_STATE_DIR}/go.mod" "${TIDY_STATE_DIR}/go.mod") 20 | DIFF_SUM=$(diff -u "${ORIGINAL_STATE_DIR}/go.sum" "${TIDY_STATE_DIR}/go.sum") 21 | 22 | if [[ -n "${DIFF_MOD}" || -n "${DIFF_SUM}" ]]; then 23 | echo "go.mod diff:" 24 | echo "${DIFF_MOD}" 25 | echo "go.sum diff:" 26 | echo "${DIFF_SUM}" 27 | echo "" 28 | printf "FAILED! go.mod and/or go.sum are NOT tidy; please run 'go mod tidy'.\n\n" 29 | exit 1 30 | fi 31 | -------------------------------------------------------------------------------- /.github/scripts/trigger-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | GH=.tool/gh 5 | 6 | bold=$(tput bold) 7 | normal=$(tput sgr0) 8 | 9 | $GH auth status 10 | 11 | # we need all of the git state to determine the next version. Since tagging is done by 12 | # the release pipeline it is possible to not have all of the tags from previous releases. 13 | git fetch --tags 14 | 15 | # populates the CHANGELOG.md and VERSION files 16 | echo "${bold}Generating changelog...${normal}" 17 | make changelog 2> /dev/null 18 | 19 | NEXT_VERSION=$(cat VERSION) 20 | 21 | if [[ "$NEXT_VERSION" == "" || "${NEXT_VERSION}" == "(Unreleased)" ]]; then 22 | echo "Could not determine the next version to release. Exiting..." 23 | exit 1 24 | fi 25 | 26 | while true; do 27 | read -p "${bold}Do you want to trigger a release for version '${NEXT_VERSION}'?${normal} [y/n] " yn 28 | case $yn in 29 | [Yy]* ) echo; break;; 30 | [Nn]* ) echo; echo "Cancelling release..."; exit;; 31 | * ) echo "Please answer yes or no.";; 32 | esac 33 | done 34 | 35 | echo "${bold}Kicking off release for ${NEXT_VERSION}${normal}..." 36 | echo 37 | $GH workflow run release.yaml -f version=${NEXT_VERSION} 38 | 39 | echo 40 | echo "${bold}Waiting for release to start...${normal}" 41 | sleep 10 42 | 43 | set +e 44 | 45 | echo "${bold}Head to the release workflow to monitor the release:${normal} $($GH run list --workflow=release.yaml --limit=1 --json url --jq '.[].url')" 46 | id=$($GH run list --workflow=release.yaml --limit=1 --json databaseId --jq '.[].databaseId') 47 | $GH run watch $id --exit-status || (echo ; echo "${bold}Logs of failed step:${normal}" && GH_PAGER="" $GH run view $id --log-failed) 48 | -------------------------------------------------------------------------------- /.github/workflows/copy-listing-from-r2.yaml: -------------------------------------------------------------------------------- 1 | name: 'Sync listing from R2 to S3' 2 | on: 3 | # allow for kicking off DB builds manually 4 | workflow_dispatch: 5 | 6 | # allow invoking from another workflow 7 | workflow_call: 8 | 9 | env: 10 | CGO_ENABLED: "0" 11 | SLACK_NOTIFICATIONS: true 12 | FORCE_COLOR: true 13 | 14 | jobs: 15 | sync-listing-file: 16 | name: "Sync listing file" 17 | 18 | runs-on: ubuntu-22.04 19 | steps: 20 | 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 22 | 23 | - name: Bootstrap environment 24 | uses: ./.github/actions/bootstrap 25 | 26 | - name: Download the R2 listing file 27 | run: curl --fail -O https://grype.anchore.io/databases/listing.json 28 | 29 | - name: Upload listing file 30 | run: | 31 | uv run \ 32 | grype-db-manager \ 33 | -c ./config/grype-db-manager/publish-production.yaml \ 34 | listing upload listing.json 35 | env: 36 | AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }} 37 | AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }} 38 | 39 | - uses: 8398a7/action-slack@1750b5085f3ec60384090fb7c52965ef822e869e #v3.18.0 40 | if: ${{ failure() && env.SLACK_NOTIFICATIONS == 'true' }} 41 | with: 42 | status: ${{ job.status }} 43 | fields: workflow,eventName,job 44 | text: Sync of the Grype DB listing file from R2 to S3 has failed 45 | env: 46 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }} 47 | 48 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-automation.yaml: -------------------------------------------------------------------------------- 1 | name: Dependabot Automation 2 | on: 3 | pull_request: 4 | 5 | permissions: 6 | pull-requests: write 7 | 8 | jobs: 9 | run: 10 | uses: anchore/workflows/.github/workflows/dependabot-automation.yaml@main 11 | -------------------------------------------------------------------------------- /.github/workflows/oss-project-board-add.yaml: -------------------------------------------------------------------------------- 1 | name: Add to OSS board 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - reopened 8 | - transferred 9 | - labeled 10 | 11 | jobs: 12 | 13 | run: 14 | uses: "anchore/workflows/.github/workflows/oss-project-board-add.yaml@main" 15 | secrets: 16 | token: ${{ secrets.OSS_PROJECT_GH_TOKEN }} 17 | -------------------------------------------------------------------------------- /.github/workflows/remove-awaiting-response-label.yaml: -------------------------------------------------------------------------------- 1 | name: "Manage Awaiting Response Label" 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | jobs: 8 | run: 9 | uses: "anchore/workflows/.github/workflows/remove-awaiting-response-label.yaml@main" 10 | secrets: 11 | token: ${{ secrets.OSS_PROJECT_GH_TOKEN }} 12 | -------------------------------------------------------------------------------- /.github/workflows/update-anchore-dependencies.yml: -------------------------------------------------------------------------------- 1 | name: PR to update Anchore dependencies 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | repos: 6 | description: "List of dependencies to update" 7 | required: true 8 | type: string 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | update: 15 | runs-on: ubuntu-latest 16 | if: github.repository_owner == 'anchore' # only run for main repo (not forks) 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 19 | 20 | - name: Bootstrap environment 21 | uses: ./.github/actions/bootstrap 22 | with: 23 | tools: false 24 | bootstrap-apt-packages: "" 25 | 26 | - name: Update dependencies 27 | id: update 28 | uses: anchore/workflows/.github/actions/update-go-dependencies@main 29 | with: 30 | repos: ${{ github.event.inputs.repos }} 31 | 32 | - uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a #v2.1.0 33 | id: generate-token 34 | with: 35 | app_id: ${{ secrets.TOKEN_APP_ID }} 36 | private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }} 37 | 38 | - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e #v7.0.8 39 | with: 40 | signoff: true 41 | delete-branch: true 42 | draft: ${{ steps.update.outputs.draft }} 43 | # do not change this branch, as other workflows depend on it 44 | branch: auto/integration 45 | labels: dependencies,pre-release 46 | commit-message: "chore(deps): update anchore dependencies" 47 | title: "chore(deps): update anchore dependencies" 48 | body: ${{ steps.update.outputs.summary }} 49 | token: ${{ steps.generate-token.outputs.token }} 50 | -------------------------------------------------------------------------------- /.github/workflows/update-generated-code.yaml: -------------------------------------------------------------------------------- 1 | name: PR to update generated code 2 | on: 3 | schedule: 4 | - cron: "0 1 * * 1" # every monday at 1 AM 5 | 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: read 10 | 11 | env: 12 | SLACK_NOTIFICATIONS: true 13 | 14 | jobs: 15 | run-code-gen: 16 | name: "Run code generation" 17 | runs-on: ubuntu-latest 18 | if: github.repository == 'anchore/grype-db' # only run for main repo 19 | steps: 20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 21 | 22 | - name: Bootstrap environment 23 | uses: ./.github/actions/bootstrap 24 | 25 | - run: | 26 | make generate-processor-code 27 | 28 | - uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a #v2.1.0 29 | id: generate-token 30 | with: 31 | app_id: ${{ secrets.TOKEN_APP_ID }} 32 | private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }} 33 | 34 | - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e #v7.0.8 35 | with: 36 | signoff: true 37 | delete-branch: true 38 | branch: auto/latest-code-gen 39 | labels: dependencies 40 | commit-message: "chore(deps): update generated code" 41 | title: "chore(deps): update generated code" 42 | body: | 43 | Update generated code from external sources 44 | token: ${{ steps.generate-token.outputs.token }} 45 | 46 | - uses: 8398a7/action-slack@1750b5085f3ec60384090fb7c52965ef822e869e #v3.18.0 47 | with: 48 | status: ${{ job.status }} 49 | fields: workflow,eventName,job 50 | text: Grype-DB generated code update failed 51 | env: 52 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }} 53 | if: ${{ failure() && env.SLACK_NOTIFICATIONS == 'true' }} -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "data/vulnerability-match-labels"] 2 | path = data/vulnerability-match-labels 3 | url = https://github.com/anchore/vulnerability-match-labels.git 4 | branch = main 5 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | release: 2 | # If set to auto, will mark the release as not ready for production 3 | # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 4 | # If set to true, will mark the release as not ready for production. 5 | prerelease: auto 6 | 7 | project_name: grype-db 8 | 9 | env: 10 | # required to support multi architecture docker builds 11 | - DOCKER_CLI_EXPERIMENTAL=enabled 12 | - CGO_ENABLED=0 13 | 14 | builds: 15 | 16 | - id: linux-build 17 | goos: 18 | - linux 19 | goarch: 20 | - amd64 21 | - arm64 22 | binary: &binary grype-db 23 | dir: &directory ./cmd/grype-db 24 | # Set the modified timestamp on the output binary to the git timestamp (to ensure a reproducible build) 25 | mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}' 26 | ldflags: &build-ldflags | 27 | -w 28 | -X github.com/anchore/grype-db/cmd/grype-db/application.version={{.Version}} 29 | -X github.com/anchore/grype-db/cmd/grype-db/application.gitCommit={{.Commit}} 30 | -X github.com/anchore/grype-db/cmd/grype-db/application.buildDate={{.Date}} 31 | -X github.com/anchore/grype-db/cmd/grype-db/application.gitDescription={{.Summary}} 32 | 33 | - id: darwin-build 34 | goos: 35 | - darwin 36 | goarch: 37 | - amd64 38 | - arm64 39 | binary: *binary 40 | dir: *directory 41 | mod_timestamp: *build-timestamp 42 | ldflags: *build-ldflags 43 | 44 | archives: 45 | - format: tar.gz 46 | -------------------------------------------------------------------------------- /.grype-db-manager.yaml: -------------------------------------------------------------------------------- 1 | data: !include config/grype-db-manager/include.d/data.yaml 2 | 3 | grype-db: !include config/grype-db-manager/include.d/grype-db-local-build.yaml 4 | 5 | # note: do not put any values here! 6 | # distribution: 7 | # ... 8 | 9 | validate: !include config/grype-db-manager/include.d/validate.yaml 10 | -------------------------------------------------------------------------------- /.vunnel.yaml: -------------------------------------------------------------------------------- 1 | root: ./data/vunnel 2 | 3 | log: 4 | slim: true 5 | level: debug 6 | 7 | providers: 8 | ubuntu: 9 | # there is a lot of IO when running git log commands in this provider, so some concurrency helps here 10 | max_workers: 10 11 | 12 | nvd: 13 | # apply community-provided overrides to the NVD data 14 | # sourced from the https://github.com/anchore/nvd-data-overrides repo 15 | overrides_enabled: true 16 | 17 | # we're getting a lot of 503s and intermittent failures from the NVD API, so we're going to retry a few times 18 | request_timeout: 125 19 | request_retry_count: 15 20 | runtime: 21 | on_error: 22 | retry_count: 10 23 | retry_delay: 60 -------------------------------------------------------------------------------- /.yardstick.yaml: -------------------------------------------------------------------------------- 1 | store-root: data/yardstick 2 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | A release of grype-db comprises: 4 | - a new semver git tag from the current tip of the main branch 5 | - a new [github release](https://github.com/anchore/grype-db/releases) with a changelog and archived binary assets 6 | 7 | Ideally releasing should be done often with small increments when possible. Unless a 8 | breaking change is blocking the release, or no fixes/features have been merged, a good 9 | target release cadence is between every 1 or 2 weeks. 10 | 11 | 12 | ## Creating a release 13 | 14 | This release process itself should be as automated as possible, and has only a few steps: 15 | 16 | 1. **Trigger a new release with `make release`**. At this point you'll see a preview 17 | changelog in the terminal. If you're happy with the changelog, press `y` to continue, otherwise 18 | you can abort and adjust the labels on the PRs and issues to be included in the release and 19 | re-run the release trigger command. 20 | 21 | 1. A release admin must approve the release on the GitHub Actions [release pipeline](https://github.com/anchore/grype-db/actions/workflows/release.yaml) run page. 22 | Once approved, the release pipeline will generate all assets and publish a GitHub Release. 23 | 24 | 25 | ## Retracting a release 26 | 27 | If a release is found to be problematic, it can be retracted with the following steps: 28 | 29 | - Deleting the GitHub Release 30 | - Add a new `retract` entry in the go.mod for the versioned release 31 | 32 | **Note**: do not delete release tags from the git repository since there may already be references to the release 33 | in the go proxy, which will cause confusion when trying to reuse the tag later (the H1 hash will not match and there 34 | will be a warning when users try to pull the new release). 35 | -------------------------------------------------------------------------------- /cmd/grype-db/application/cache.go: -------------------------------------------------------------------------------- 1 | package application 2 | 3 | type Cache struct { 4 | Directory string `yaml:"dir" json:"dir" mapstructure:"dir"` 5 | } 6 | -------------------------------------------------------------------------------- /cmd/grype-db/application/development.go: -------------------------------------------------------------------------------- 1 | package application 2 | 3 | import "github.com/spf13/viper" 4 | 5 | type Development struct { 6 | ProfileCPU bool `yaml:"profile-cpu" json:"profile-cpu" mapstructure:"profile-cpu"` 7 | ProfileMem bool `yaml:"profile-mem" json:"profile-mem" mapstructure:"profile-mem"` 8 | } 9 | 10 | func (c Development) loadDefaultValues(v *viper.Viper) { 11 | v.SetDefault("dev.profile-cpu", c.ProfileCPU) // zero-value (false) or the current instance value 12 | v.SetDefault("dev.profile-mem", c.ProfileMem) // zero-value (false) or the current instance value 13 | } 14 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/cli.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/anchore/grype-db/cmd/grype-db/application" 7 | "github.com/anchore/grype-db/cmd/grype-db/cli/commands" 8 | ) 9 | 10 | type config struct { 11 | app *application.Application 12 | } 13 | 14 | type Option func(*config) 15 | 16 | func WithApplication(app *application.Application) Option { 17 | return func(config *config) { 18 | config.app = app 19 | } 20 | } 21 | 22 | func New(opts ...Option) *cobra.Command { 23 | cfg := &config{ 24 | app: application.New(), 25 | } 26 | for _, fn := range opts { 27 | fn(cfg) 28 | } 29 | 30 | app := cfg.app 31 | 32 | cache := commands.Cache(app) 33 | cache.AddCommand(commands.CacheStatus(app)) 34 | cache.AddCommand(commands.CacheDelete(app)) 35 | cache.AddCommand(commands.CacheBackup(app)) 36 | cache.AddCommand(commands.CacheRestore(app)) 37 | 38 | root := commands.Root(app) 39 | root.AddCommand(commands.Version(app)) 40 | root.AddCommand(commands.Pull(app)) 41 | root.AddCommand(commands.Build(app)) 42 | root.AddCommand(commands.Package(app)) 43 | root.AddCommand(commands.ListProviders(app)) 44 | root.AddCommand(cache) 45 | 46 | return root 47 | } 48 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/commands/cache.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/anchore/grype-db/cmd/grype-db/application" 7 | ) 8 | 9 | func Cache(_ *application.Application) *cobra.Command { 10 | cmd := &cobra.Command{ 11 | Use: "cache", 12 | Short: "manage the local pull cache", 13 | Args: cobra.NoArgs, 14 | } 15 | 16 | commonConfiguration(nil, cmd, nil) 17 | return cmd 18 | } 19 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/commands/package.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/scylladb/go-set/strset" 7 | "github.com/spf13/cobra" 8 | "github.com/spf13/pflag" 9 | "github.com/spf13/viper" 10 | 11 | "github.com/anchore/grype-db/cmd/grype-db/application" 12 | "github.com/anchore/grype-db/cmd/grype-db/cli/options" 13 | "github.com/anchore/grype-db/pkg/process" 14 | ) 15 | 16 | var _ options.Interface = &buildConfig{} 17 | 18 | type packageConfig struct { 19 | options.DBLocation `yaml:"build" json:"build" mapstructure:"build"` 20 | options.Package `yaml:"package" json:"package" mapstructure:"package"` 21 | } 22 | 23 | func (o *packageConfig) AddFlags(flags *pflag.FlagSet) { 24 | options.AddAllFlags(flags, &o.DBLocation, &o.Package) 25 | } 26 | 27 | func (o *packageConfig) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 28 | return options.BindAllFlags(flags, v, &o.DBLocation, &o.Package) 29 | } 30 | 31 | func Package(app *application.Application) *cobra.Command { 32 | cfg := packageConfig{ 33 | DBLocation: options.DefaultDBLocation(), 34 | Package: options.DefaultPackage(), 35 | } 36 | 37 | cmd := &cobra.Command{ 38 | Use: "package", 39 | Short: "package the already built database file into an archive ready for upload and serving", 40 | Args: cobra.NoArgs, 41 | PreRunE: app.Setup(&cfg), 42 | RunE: func(cmd *cobra.Command, _ []string) error { 43 | if cfg.OverrideArchiveExtension != "" { 44 | if !strset.New("tar.gz", "tar.zst").Has(cfg.OverrideArchiveExtension) { 45 | return fmt.Errorf("archive-extension must be 'tar.gz' or 'tar.zst'") 46 | } 47 | } 48 | 49 | return app.Run(cmd.Context(), async(func() error { 50 | return runPackage(cfg) 51 | })) 52 | }, 53 | } 54 | 55 | commonConfiguration(app, cmd, &cfg) 56 | 57 | return cmd 58 | } 59 | 60 | func runPackage(cfg packageConfig) error { 61 | return process.Package(cfg.DBLocation.Directory, cfg.PublishBaseURL, cfg.OverrideArchiveExtension) 62 | } 63 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/commands/test-fixtures/test-root/test-provider/input/some-input-file.txt: -------------------------------------------------------------------------------- 1 | input-file -------------------------------------------------------------------------------- /cmd/grype-db/cli/commands/test-fixtures/test-root/test-provider/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "provider": "wolfi", 3 | "urls": [ 4 | "https://packages.wolfi.dev/os/security.json" 5 | ], 6 | "store": "sqlite", 7 | "timestamp": "2024-03-25T01:26:38.371438+00:00", 8 | "version": 1, 9 | "listing": { 10 | "digest": "00dfa461d5d03954", 11 | "path": "checksums", 12 | "algorithm": "xxh64" 13 | }, 14 | "schema": { 15 | "version": "1.0.1", 16 | "url": "https://raw.githubusercontent.com/anchore/vunnel/main/schema/provider-workspace-state/schema-1.0.1.json" 17 | } 18 | } -------------------------------------------------------------------------------- /cmd/grype-db/cli/commands/test-fixtures/test-root/test-provider/results/results.db: -------------------------------------------------------------------------------- 1 | results-file -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/cache_archive.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &CacheArchive{} 9 | 10 | type CacheArchive struct { 11 | // bound options 12 | Path string `yaml:"archive" json:"archive" mapstructure:"archive"` 13 | 14 | // unbound options 15 | // (none) 16 | } 17 | 18 | func DefaultCacheArchive() CacheArchive { 19 | return CacheArchive{ 20 | Path: "./grype-db-cache.tar.gz", 21 | } 22 | } 23 | 24 | func (o *CacheArchive) AddFlags(flags *pflag.FlagSet) { 25 | flags.StringVarP( 26 | &o.Path, 27 | "path", "", o.Path, 28 | "path to the grype-db cache archive", 29 | ) 30 | } 31 | 32 | func (o *CacheArchive) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 33 | // set default values for bound struct items 34 | if err := Bind(v, "cache.archive", flags.Lookup("path")); err != nil { 35 | return err 36 | } 37 | 38 | // set default values for non-bound struct items 39 | // (none) 40 | 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/cache_restore.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &CacheRestore{} 9 | 10 | type CacheRestore struct { 11 | // bound options 12 | DeleteExisting bool `yaml:"delete-existing" json:"delete-existing" mapstructure:"delete-existing"` 13 | 14 | // unbound options 15 | // (none) 16 | } 17 | 18 | func DefaultCacheRestore() CacheRestore { 19 | return CacheRestore{ 20 | DeleteExisting: false, 21 | } 22 | } 23 | 24 | func (o *CacheRestore) AddFlags(flags *pflag.FlagSet) { 25 | flags.BoolVarP( 26 | &o.DeleteExisting, 27 | "delete-existing", "d", o.DeleteExisting, 28 | "delete existing cache before restoring from backup", 29 | ) 30 | } 31 | 32 | func (o *CacheRestore) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 33 | // set default values for bound struct items 34 | if err := Bind(v, "restore.delete-existing", flags.Lookup("delete-existing")); err != nil { 35 | return err 36 | } 37 | 38 | // set default values for non-bound struct items 39 | // (none) 40 | 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/db_location.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &DBLocation{} 9 | 10 | type DBLocation struct { 11 | // bound options 12 | Directory string `yaml:"dir" json:"dir" mapstructure:"dir"` 13 | 14 | // unbound options 15 | // (none) 16 | } 17 | 18 | func DefaultDBLocation() DBLocation { 19 | return DBLocation{ 20 | Directory: "./build", 21 | } 22 | } 23 | 24 | func (o *DBLocation) AddFlags(flags *pflag.FlagSet) { 25 | flags.StringVarP( 26 | &o.Directory, 27 | "dir", "d", o.Directory, 28 | "directory where the database is written", 29 | ) 30 | } 31 | 32 | func (o *DBLocation) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 33 | // set default values for bound struct items 34 | if err := Bind(v, "build.dir", flags.Lookup("dir")); err != nil { 35 | return err 36 | } 37 | 38 | // set default values for non-bound struct items 39 | // (none) 40 | 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/format.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/pflag" 7 | "github.com/spf13/viper" 8 | ) 9 | 10 | var _ Interface = &Format{} 11 | 12 | type Format struct { 13 | Output string `yaml:"output" json:"output" mapstructure:"output"` 14 | AllowableFormats []string `yaml:"-" json:"-" mapstructure:"-"` 15 | } 16 | 17 | func (o *Format) AddFlags(flags *pflag.FlagSet) { 18 | flags.StringVarP( 19 | &o.Output, 20 | "output", "o", o.Output, 21 | fmt.Sprintf("output format to report results in (allowable values: %s)", o.AllowableFormats), 22 | ) 23 | } 24 | 25 | func (o *Format) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 26 | return Bind(v, "output", flags.Lookup("output")) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/options.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/hashicorp/go-multierror" 5 | "github.com/spf13/pflag" 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | type Interface interface { 10 | AddFlags(*pflag.FlagSet) 11 | BindFlags(*pflag.FlagSet, *viper.Viper) error 12 | } 13 | 14 | func AddAllFlags(flags *pflag.FlagSet, i ...Interface) { 15 | for _, o := range i { 16 | o.AddFlags(flags) 17 | } 18 | } 19 | 20 | func BindAllFlags(flags *pflag.FlagSet, v *viper.Viper, i ...Interface) error { 21 | var errs error 22 | for _, o := range i { 23 | if err := o.BindFlags(flags, v); err != nil { 24 | errs = multierror.Append(errs, err) 25 | } 26 | } 27 | return errs 28 | } 29 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/package.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &Package{} 9 | 10 | type Package struct { 11 | // bound options 12 | PublishBaseURL string `yaml:"publish-base-url" json:"publish-base-url" mapstructure:"publish-base-url"` 13 | OverrideArchiveExtension string `yaml:"override-archive-extension" json:"override-archive-extension" mapstructure:"override-archive-extension"` 14 | 15 | // unbound options 16 | // (none) 17 | } 18 | 19 | func DefaultPackage() Package { 20 | return Package{ 21 | PublishBaseURL: "https://localhost:8080/grype/databases", 22 | } 23 | } 24 | 25 | func (o *Package) AddFlags(flags *pflag.FlagSet) { 26 | flags.StringVarP( 27 | &o.PublishBaseURL, 28 | "publish-base-url", "u", o.PublishBaseURL, 29 | "the base URL used for reference in the listing.json index file", 30 | ) 31 | 32 | flags.StringVarP( 33 | &o.OverrideArchiveExtension, 34 | "archive-extension", "e", 35 | o.OverrideArchiveExtension, 36 | "Override the extension used during DB archiving (default is 'tar.gz' or 'tar.zst' based on the grype DB schema)") 37 | } 38 | 39 | func (o *Package) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 40 | // set default values for bound struct items 41 | if err := Bind(v, "package.publish-base-url", flags.Lookup("publish-base-url")); err != nil { 42 | return err 43 | } 44 | 45 | if err := viper.BindPFlag("package.override-archive-extension", flags.Lookup("archive-extension")); err != nil { 46 | return err 47 | } 48 | 49 | // set default values for non-bound struct items 50 | // (none) 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/provider.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | 7 | "github.com/anchore/grype-db/pkg/provider" 8 | ) 9 | 10 | var _ Interface = &Provider{} 11 | 12 | type Provider struct { 13 | // bound options 14 | Selection `yaml:",inline" mapstructure:",squash"` 15 | 16 | // unbound options 17 | Store `yaml:",inline" mapstructure:",squash"` 18 | Vunnel Vunnel `yaml:"vunnel" json:"vunnel" mapstructure:"vunnel"` 19 | Configs []provider.Config `yaml:"configs" json:"configs" mapstructure:"configs"` 20 | } 21 | 22 | func (o Provider) Redact() { 23 | o.Vunnel.Redact() 24 | for _, v := range o.Configs { 25 | v.Redact() 26 | } 27 | } 28 | 29 | func DefaultProvider() Provider { 30 | return Provider{ 31 | Store: DefaultStore(), 32 | Vunnel: DefaultVunnel(), 33 | Selection: DefaultSelection(), 34 | Configs: nil, 35 | } 36 | } 37 | 38 | func (o *Provider) AddFlags(flags *pflag.FlagSet) { 39 | // bound options 40 | // (none) 41 | 42 | // unbound options 43 | // (none) 44 | 45 | // nested options 46 | o.Vunnel.AddFlags(flags) 47 | o.Store.AddFlags(flags) 48 | o.Selection.AddFlags(flags) 49 | } 50 | 51 | func (o *Provider) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 52 | // set default values for bound struct items 53 | // (none) 54 | 55 | // set default values for non-bound struct items 56 | v.SetDefault("provider.configs", o.Configs) 57 | 58 | // nested options 59 | if err := o.Vunnel.BindFlags(flags, v); err != nil { 60 | return err 61 | } 62 | if err := o.Selection.BindFlags(flags, v); err != nil { 63 | return err 64 | } 65 | return o.Store.BindFlags(flags, v) 66 | } 67 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/provider_selection.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &Provider{} 9 | 10 | type Selection struct { 11 | // bound options 12 | IncludeFilter []string `yaml:"include-filter" json:"include-filter" mapstructure:"include-filter"` 13 | 14 | // unbound options 15 | // (none) 16 | } 17 | 18 | func DefaultSelection() Selection { 19 | return Selection{} 20 | } 21 | 22 | func (o *Selection) AddFlags(flags *pflag.FlagSet) { 23 | // bound options 24 | flags.StringArrayVarP( 25 | &o.IncludeFilter, 26 | "provider-name", "p", o.IncludeFilter, 27 | "one or more provider names to filter building a DB for (default: empty = all)", 28 | ) 29 | 30 | // unbound options 31 | // (none) 32 | } 33 | 34 | func (o *Selection) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 35 | // set default values for bound struct items 36 | if err := Bind(v, "provider.include-filter", flags.Lookup("provider-name")); err != nil { 37 | return err 38 | } 39 | 40 | // set default values for non-bound struct items 41 | // (none) 42 | 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/pull.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &Pull{} 9 | 10 | type Pull struct { 11 | // bound options 12 | Parallelism int `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"` 13 | 14 | // unbound options 15 | // (none) 16 | } 17 | 18 | func DefaultPull() Pull { 19 | return Pull{ 20 | Parallelism: 4, 21 | } 22 | } 23 | 24 | func (o *Pull) AddFlags(flags *pflag.FlagSet) { 25 | flags.IntVarP( 26 | &o.Parallelism, 27 | "parallelism", "", o.Parallelism, 28 | "number of vulnerability providers to update concurrently", 29 | ) 30 | } 31 | 32 | func (o *Pull) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 33 | // set default values for bound struct items 34 | if err := Bind(v, "pull.parallelism", flags.Lookup("parallelism")); err != nil { 35 | return err 36 | } 37 | 38 | // set default values for non-bound struct items 39 | // (none) 40 | 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/results.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &Results{} 9 | 10 | type Results struct { 11 | ResultsOnly bool `yaml:"results-only" json:"results-only" mapstructure:"results-only"` 12 | } 13 | 14 | func (r Results) AddFlags(flags *pflag.FlagSet) { 15 | flags.BoolVarP( 16 | &r.ResultsOnly, 17 | "results-only", "r", r.ResultsOnly, 18 | "only backup the results and ignore the input directories (default: false)", 19 | ) 20 | } 21 | 22 | func (r Results) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { 23 | return Bind(v, "results.results-only", flags.Lookup("results-only")) 24 | } 25 | 26 | func DefaultResults() Results { 27 | return Results{ResultsOnly: false} 28 | } 29 | -------------------------------------------------------------------------------- /cmd/grype-db/cli/options/store.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "github.com/spf13/pflag" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var _ Interface = &Store{} 9 | 10 | type Store struct { 11 | // bound options 12 | // (none) 13 | 14 | // unbound options 15 | Root string `yaml:"root" json:"root" mapstructure:"root"` 16 | } 17 | 18 | func DefaultStore() Store { 19 | return Store{ 20 | Root: "./data", 21 | } 22 | } 23 | 24 | func (o *Store) AddFlags(_ *pflag.FlagSet) { 25 | // bound options 26 | // (none) 27 | 28 | // unbound options 29 | // (none) 30 | } 31 | 32 | func (o *Store) BindFlags(_ *pflag.FlagSet, v *viper.Viper) error { 33 | // set default values for bound struct items 34 | // (none) 35 | 36 | // set default values for non-bound struct items 37 | v.SetDefault("provider.root", o.Root) 38 | 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /cmd/grype-db/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "os/signal" 7 | 8 | "github.com/gookit/color" 9 | 10 | "github.com/anchore/grype-db/cmd/grype-db/cli" 11 | "github.com/anchore/grype-db/internal/log" 12 | ) 13 | 14 | func main() { 15 | cmd := cli.New() 16 | 17 | // drive application control from a single context which can be cancelled (notifying the event loop to stop) 18 | ctx, cancel := context.WithCancel(context.Background()) 19 | cmd.SetContext(ctx) 20 | 21 | // note: it is important to always do signal handling from the main package. In this way if grype-db is used 22 | // as a lib a refactor would not need to be done (since anything from the main package cannot be imported this 23 | // nicely enforces this constraint) 24 | signals := make(chan os.Signal, 10) // Note: A buffered channel is recommended for this; see https://golang.org/pkg/os/signal/#Notify 25 | signal.Notify(signals, os.Interrupt) 26 | 27 | defer func() { 28 | signal.Stop(signals) 29 | cancel() 30 | }() 31 | 32 | go func() { 33 | select { 34 | case <-signals: // first signal, cancel context 35 | log.Trace("signal interrupt, stop requested") 36 | cancel() 37 | case <-ctx.Done(): 38 | } 39 | <-signals // second signal, hard exit 40 | log.Trace("signal interrupt, killing") 41 | os.Exit(1) 42 | }() 43 | 44 | if err := cmd.Execute(); err != nil { 45 | color.Red.Printf("error: %v", err) 46 | defer os.Exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /config/grype-db-manager/acceptance-pr.yaml: -------------------------------------------------------------------------------- 1 | # this configuration is intended to be used for running acceptance tests on PRs 2 | 3 | data: !include config/grype-db-manager/include.d/data.yaml 4 | 5 | grype-db: !include config/grype-db-manager/include.d/grype-db-local-build.yaml 6 | 7 | # note: do not include the distribution config here. It is only used for the production/staging pipelines. 8 | # distribution: ... 9 | 10 | validate: !include config/grype-db-manager/include.d/validate.yaml 11 | -------------------------------------------------------------------------------- /config/grype-db-manager/include.d/data.yaml: -------------------------------------------------------------------------------- 1 | # data: 2 | 3 | root: data/manager 4 | vunnel-root: data/vunnel 5 | yardstick-root: data/yardstick -------------------------------------------------------------------------------- /config/grype-db-manager/include.d/distribution-production-r2.yaml: -------------------------------------------------------------------------------- 1 | # distribution: 2 | 3 | listing-file-name: listing.json 4 | s3-path: databases 5 | s3-bucket: oss-prod-anchore 6 | aws-region: auto 7 | download-url-prefix: https://grype.anchore.io 8 | -------------------------------------------------------------------------------- /config/grype-db-manager/include.d/distribution-production.yaml: -------------------------------------------------------------------------------- 1 | # distribution: 2 | 3 | listing-file-name: listing.json 4 | s3-path: grype/databases 5 | s3-bucket: toolbox-data.anchore.io 6 | aws-region: us-west-2 7 | download-url-prefix: https://toolbox-data.anchore.io 8 | -------------------------------------------------------------------------------- /config/grype-db-manager/include.d/distribution-staging.yaml: -------------------------------------------------------------------------------- 1 | # distribution: 2 | 3 | listing-file-name: listing.json 4 | s3-path: grype/staging-databases 5 | s3-bucket: toolbox-data.anchore.io 6 | aws-region: us-west-2 7 | download-url-prefix: https://toolbox-data.anchore.io 8 | -------------------------------------------------------------------------------- /config/grype-db-manager/include.d/grype-db-local-build-r2.yaml: -------------------------------------------------------------------------------- 1 | # grype-db: 2 | 3 | # use the current repo at the current commit as the source of truth for the grype-db build source. 4 | # note: assume this will be invoked from the root of the repo 5 | version: file://. 6 | 7 | # grype-db application configuration to use. 8 | # note: assume this will be invoked from the root of the repo 9 | config: config/grype-db/publish-nightly-r2.yaml 10 | -------------------------------------------------------------------------------- /config/grype-db-manager/include.d/grype-db-local-build.yaml: -------------------------------------------------------------------------------- 1 | # grype-db: 2 | 3 | # use the current repo at the current commit as the source of truth for the grype-db build source. 4 | # note: assume this will be invoked from the root of the repo 5 | version: file://. 6 | 7 | # grype-db application configuration to use. 8 | # note: assume this will be invoked from the root of the repo 9 | config: config/grype-db/publish-nightly.yaml 10 | -------------------------------------------------------------------------------- /config/grype-db-manager/publish-production-r2.yaml: -------------------------------------------------------------------------------- 1 | # this configuration is intended to be used for nightly builds of the database in production 2 | 3 | data: !include config/grype-db-manager/include.d/data.yaml 4 | 5 | grype-db: !include config/grype-db-manager/include.d/grype-db-local-build-r2.yaml 6 | 7 | distribution: !include config/grype-db-manager/include.d/distribution-production-r2.yaml 8 | 9 | validate: !include config/grype-db-manager/include.d/validate.yaml 10 | 11 | assert-aws-credentials: false -------------------------------------------------------------------------------- /config/grype-db-manager/publish-production.yaml: -------------------------------------------------------------------------------- 1 | # this configuration is intended to be used for nightly builds of the database in production 2 | 3 | data: !include config/grype-db-manager/include.d/data.yaml 4 | 5 | grype-db: !include config/grype-db-manager/include.d/grype-db-local-build.yaml 6 | 7 | distribution: !include config/grype-db-manager/include.d/distribution-production.yaml 8 | 9 | validate: !include config/grype-db-manager/include.d/validate.yaml 10 | -------------------------------------------------------------------------------- /config/grype-db-manager/publish-staging.yaml: -------------------------------------------------------------------------------- 1 | # this configuration is intended to be used for ad-hoc builds of the database to the staging environment 2 | 3 | data: !include config/grype-db-manager/include.d/data.yaml 4 | 5 | grype-db: !include config/grype-db-manager/include.d/grype-db-local-build.yaml 6 | 7 | distribution: !include config/grype-db-manager/include.d/distribution-staging.yaml 8 | 9 | validate: !include config/grype-db-manager/include.d/validate.yaml 10 | -------------------------------------------------------------------------------- /config/grype-db/publish-nightly-r2.yaml: -------------------------------------------------------------------------------- 1 | # this is a grype-db application configuration file intended for use with the daily db publisher workflow 2 | 3 | provider: 4 | root: data/vunnel 5 | 6 | # No manual configs are provided since 'provider.vunnel.generateConfigs' is set to true 7 | # this means that well run vunnel to get the list of supported providers. All supported providers 8 | # will be included in the database build. This prevents the need from manually updating this file 9 | # for every new provider that is added. 10 | # 11 | # Any providers that should be excluded from processing should be added to the 'provider.vunnel.excludeProviders' list. 12 | configs: 13 | - name: nvd 14 | - name: alpine 15 | - name: amazon 16 | - name: chainguard 17 | - name: debian 18 | - name: epss 19 | - name: github 20 | - name: kev 21 | - name: mariner 22 | - name: oracle 23 | - name: rhel 24 | - name: sles 25 | - name: ubuntu 26 | - name: wolfi 27 | 28 | vunnel: 29 | executor: docker 30 | docker-tag: latest 31 | generate-configs: false 32 | env: 33 | GITHUB_TOKEN: $GITHUB_TOKEN 34 | NVD_API_KEY: $NVD_API_KEY 35 | 36 | pull: 37 | parallelism: 4 38 | 39 | package: 40 | # required for v5 41 | publish-base-url: https://grype.anchore.io/databases 42 | -------------------------------------------------------------------------------- /config/grype-db/publish-nightly.yaml: -------------------------------------------------------------------------------- 1 | # this is a grype-db application configuration file intended for use with the daily db publisher workflow 2 | 3 | provider: 4 | root: data/vunnel 5 | 6 | # No manual configs are provided since 'provider.vunnel.generateConfigs' is set to true 7 | # this means that well run vunnel to get the list of supported providers. All supported providers 8 | # will be included in the database build. This prevents the need from manually updating this file 9 | # for every new provider that is added. 10 | # 11 | # Any providers that should be excluded from processing should be added to the 'provider.vunnel.excludeProviders' list. 12 | configs: 13 | - name: nvd 14 | - name: alpine 15 | - name: amazon 16 | - name: chainguard 17 | - name: debian 18 | - name: epss 19 | - name: github 20 | - name: kev 21 | - name: mariner 22 | - name: oracle 23 | - name: rhel 24 | - name: sles 25 | - name: ubuntu 26 | - name: wolfi 27 | 28 | vunnel: 29 | executor: docker 30 | docker-tag: latest 31 | generate-configs: false 32 | env: 33 | GITHUB_TOKEN: $GITHUB_TOKEN 34 | NVD_API_KEY: $NVD_API_KEY 35 | 36 | pull: 37 | parallelism: 4 38 | 39 | package: 40 | # required for v5 41 | publish-base-url: https://toolbox-data.anchore.io/grype/databases 42 | -------------------------------------------------------------------------------- /data/yardstick/labels: -------------------------------------------------------------------------------- 1 | ../vulnerability-match-labels/labels -------------------------------------------------------------------------------- /internal/bus/bus.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package bus provides access to a singleton instance of an event bus (provided by the calling application). The event bus 3 | is intended to allow for the library to publish events which library consumers can subscribe to. These events 4 | can provide static information, but also have an object as a payload for which the consumer can poll for updates. 5 | This is akin to a logger, except instead of only allowing strings to be logged, rich objects that can be interacted with. 6 | 7 | Note that the singleton instance is only allowed to publish events and not subscribe to them --this is intentional. 8 | Internal library interactions should continue to use traditional in-execution-path approaches for data sharing 9 | (e.g. function returns and channels) and not depend on bus subscriptions for critical interactions (e.g. one part of the 10 | lib publishes an event and another part of the lib subscribes and reacts to that event). The bus is provided only as a 11 | means for consumers to observe events emitted from the library (such as to provide a rich UI) and not to allow 12 | consumers to augment or otherwise change execution. 13 | */ 14 | package bus 15 | 16 | import ( 17 | "github.com/wagoodman/go-partybus" 18 | 19 | "github.com/anchore/grype-db/pkg/event" 20 | ) 21 | 22 | var publisher partybus.Publisher 23 | var active bool 24 | 25 | // SetPublisher sets the singleton event bus publisher. This is optional; if no bus is provided, the library will 26 | // behave no differently than if a bus had been provided. 27 | func SetPublisher(p partybus.Publisher) { 28 | publisher = p 29 | if p != nil { 30 | active = true 31 | } 32 | } 33 | 34 | // Publish an event onto the bus. If there is no bus set by the calling application, this does nothing. 35 | func Publish(event partybus.Event) { 36 | if active { 37 | publisher.Publish(event) 38 | } 39 | } 40 | 41 | func Exit() { 42 | Publish(partybus.Event{ 43 | Type: event.Exit, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /internal/constants.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | const ApplicationName = "grype-db" 4 | -------------------------------------------------------------------------------- /internal/file/exists.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/afero" 7 | ) 8 | 9 | func Exists(fs afero.Fs, path string) bool { 10 | info, err := fs.Stat(path) 11 | if os.IsNotExist(err) { 12 | return false 13 | } 14 | return !info.IsDir() 15 | } 16 | -------------------------------------------------------------------------------- /internal/file/hasher.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "hash" 7 | "io" 8 | "strings" 9 | 10 | "github.com/spf13/afero" 11 | ) 12 | 13 | func ContentDigest(fs afero.Fs, path string, hasher hash.Hash) (string, error) { 14 | f, err := fs.Open(path) 15 | if err != nil { 16 | return "", fmt.Errorf("failed to open file '%s': %w", path, err) 17 | } 18 | defer f.Close() 19 | 20 | if _, err := io.Copy(hasher, f); err != nil { 21 | return "", fmt.Errorf("failed to hash file '%s': %w", path, err) 22 | } 23 | 24 | return hex.EncodeToString(hasher.Sum(nil)), nil 25 | } 26 | 27 | func ValidateDigest(path, expectedDigest string, hasher hash.Hash) error { 28 | actual, err := ContentDigest(afero.NewOsFs(), path, hasher) 29 | if err != nil { 30 | return fmt.Errorf("failed to hash file %q: %w", path, err) 31 | } 32 | if !strings.HasSuffix(expectedDigest, actual) { 33 | return fmt.Errorf("hash mismatch for file %q: got %q expected %q", path, actual, expectedDigest) 34 | } 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /internal/format/color.go: -------------------------------------------------------------------------------- 1 | package format 2 | 3 | import "fmt" 4 | 5 | const ( 6 | DefaultColor Color = iota + 30 7 | Red 8 | Green 9 | Yellow 10 | Blue 11 | Magenta 12 | Cyan 13 | White 14 | ) 15 | 16 | type Color uint8 17 | 18 | // TODO: not cross platform (windows...) 19 | func (c Color) Format(s string) string { 20 | return fmt.Sprintf("\x1b[%dm%s\x1b[0m", c, s) 21 | } 22 | -------------------------------------------------------------------------------- /internal/format/tprint.go: -------------------------------------------------------------------------------- 1 | package format 2 | 3 | import ( 4 | "bytes" 5 | "text/template" 6 | ) 7 | 8 | // Tprintf renders a string from a given template string and field values 9 | func Tprintf(tmpl string, data map[string]interface{}) string { 10 | t := template.Must(template.New("").Parse(tmpl)) 11 | buf := &bytes.Buffer{} 12 | if err := t.Execute(buf, data); err != nil { 13 | return "" 14 | } 15 | return buf.String() 16 | } 17 | -------------------------------------------------------------------------------- /internal/log/redactable.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | type Redactable interface { 4 | Redact() 5 | } 6 | -------------------------------------------------------------------------------- /internal/stringset.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | type Set map[string]struct{} 4 | 5 | func NewStringSet() Set { 6 | return make(Set) 7 | } 8 | 9 | func NewStringSetFromSlice(start []string) Set { 10 | ret := make(Set) 11 | for _, s := range start { 12 | ret.Add(s) 13 | } 14 | return ret 15 | } 16 | 17 | func (s Set) Add(i string) { 18 | s[i] = struct{}{} 19 | } 20 | 21 | func (s Set) Remove(i string) { 22 | delete(s, i) 23 | } 24 | 25 | func (s Set) Contains(i string) bool { 26 | _, ok := s[i] 27 | return ok 28 | } 29 | 30 | func (s Set) ToSlice() []string { 31 | ret := make([]string, len(s)) 32 | idx := 0 33 | for v := range s { 34 | ret[idx] = v 35 | idx++ 36 | } 37 | return ret 38 | } 39 | -------------------------------------------------------------------------------- /internal/tarutil/file_entry.go: -------------------------------------------------------------------------------- 1 | package tarutil 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | ) 8 | 9 | var _ Entry = (*FileEntry)(nil) 10 | 11 | type FileEntry struct { 12 | Path string 13 | } 14 | 15 | func NewEntryFromFilePath(path string) Entry { 16 | return FileEntry{ 17 | Path: path, 18 | } 19 | } 20 | 21 | func NewEntryFromFilePaths(paths ...string) []Entry { 22 | var entries []Entry 23 | for _, path := range paths { 24 | entries = append(entries, NewEntryFromFilePath(path)) 25 | } 26 | return entries 27 | } 28 | 29 | func (t FileEntry) writeEntry(tw lowLevelWriter) error { 30 | fi, err := os.Lstat(t.Path) 31 | if err != nil { 32 | return fmt.Errorf("unable to stat file %q: %w", t.Path, err) 33 | } 34 | return writeEntry(tw, t.Path, fi, func() (io.Reader, error) { 35 | return os.Open(t.Path) 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /internal/tarutil/populate.go: -------------------------------------------------------------------------------- 1 | package tarutil 2 | 3 | // PopulateWithPaths creates a compressed tar from the given paths. 4 | func PopulateWithPaths(tarPath string, filePaths ...string) error { 5 | w, err := NewWriter(tarPath) 6 | if err != nil { 7 | return err 8 | } 9 | defer w.Close() 10 | 11 | for _, entry := range NewEntryFromFilePaths(filePaths...) { 12 | if err := w.WriteEntry(entry); err != nil { 13 | return err 14 | } 15 | } 16 | 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /internal/tarutil/tar.go: -------------------------------------------------------------------------------- 1 | package tarutil 2 | 3 | import ( 4 | "archive/tar" 5 | "io" 6 | ) 7 | 8 | // Writer represents a facade for writing entries to a tar file. 9 | type Writer interface { 10 | WriteEntry(Entry) error 11 | io.Closer 12 | } 13 | 14 | // lowLevelWriter abstracts the *tar.Writer from the standard library. 15 | type lowLevelWriter interface { 16 | WriteHeader(*tar.Header) error 17 | Flush() error 18 | io.WriteCloser 19 | } 20 | 21 | // Entry represents an entry that can be written to a tar file via a tar.Writer from the standard library. 22 | type Entry interface { 23 | writeEntry(writer lowLevelWriter) error 24 | } 25 | -------------------------------------------------------------------------------- /internal/ui/config.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | type Config struct { 4 | Verbose bool 5 | Quiet bool 6 | Debug bool 7 | } 8 | -------------------------------------------------------------------------------- /internal/ui/select.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "github.com/anchore/grype-db/internal/ui/loggerui" 5 | ) 6 | 7 | func Select(cfg Config) (uis []UI) { 8 | // TODO: in the future we may support a TUI, this is the spot to select it 9 | 10 | return []UI{loggerui.New(cfg.Debug, cfg.Quiet)} 11 | } 12 | -------------------------------------------------------------------------------- /internal/ui/ui.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import "github.com/wagoodman/go-partybus" 4 | 5 | type UI interface { 6 | Setup(unsubscribe func() error) error 7 | partybus.Handler 8 | Teardown(force bool) error 9 | } 10 | -------------------------------------------------------------------------------- /internal/utils/indent.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "strings" 4 | 5 | func Indent(text, indent string) string { 6 | if len(strings.TrimSpace(text)) == 0 { 7 | return indent 8 | } 9 | if text[len(text)-1:] == "\n" { 10 | result := "" 11 | for _, j := range strings.Split(text[:len(text)-1], "\n") { 12 | result += indent + j + "\n" 13 | } 14 | return result 15 | } 16 | result := "" 17 | for _, j := range strings.Split(strings.TrimRight(text, "\n"), "\n") { 18 | result += indent + j + "\n" 19 | } 20 | return result[:len(result)-1] 21 | } 22 | -------------------------------------------------------------------------------- /manager/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = grype_db_manager 3 | omit = 4 | */__main__.py 5 | */cli/__init__.py 6 | */tests/* 7 | */site-packages/* 8 | */venv/* 9 | */.venv/* 10 | */.cache/* 11 | 12 | [report] 13 | show_missing = true 14 | fail_under = 50 15 | 16 | [html] 17 | directory = htmlcov 18 | -------------------------------------------------------------------------------- /manager/Makefile: -------------------------------------------------------------------------------- 1 | # in percent 2 | .DEFAULT_GOAL := all 3 | 4 | .PHONY: all 5 | all: static-analysis test ## Run all validations 6 | 7 | .PHONY: static-analysis 8 | static-analysis: lint ## Run all static analyses 9 | 10 | .PHONY: test 11 | test: unit ## Run all tests 12 | 13 | 14 | ## Bootstrapping targets ################################# 15 | 16 | .PHONY: bootstrap 17 | bootstrap: ## Install all dependencies 18 | $(call title,Bootstrapping dependencies) 19 | uv sync --all-extras --dev 20 | 21 | 22 | ## Static analysis targets ################################# 23 | 24 | .PHONY: lint 25 | lint: ## Show linting issues (ruff) 26 | uv run ruff format --check 27 | uv run ruff check . 28 | 29 | .PHONY: lint-fix 30 | lint-fix: format ## Fix linting issues (ruff) 31 | uv run ruff check . --fix 32 | 33 | .PHONY: format 34 | format: ## Format (ruff) 35 | uv run ruff format 36 | 37 | 38 | ## Testing targets ################################# 39 | 40 | .PHONY: unit 41 | unit: ## Run unit tests 42 | uv run pytest --cov=grype_db_manager --cov-report=html -vv tests/unit/ 43 | 44 | .PHONY: cli 45 | cli: ## Run cli tests 46 | cd tests/cli && uv run make 47 | 48 | 49 | ## DB Testing targets ################################# 50 | 51 | .PHONY: db-acceptance 52 | db-acceptance: ## Run DB acceptance tests 53 | @ echo "Building and testing DB schema=$(schema_version)" 54 | if [ -z "$(schema_version)" ]; then \ 55 | echo "schema_version is not set"; \ 56 | exit 1; \ 57 | fi 58 | 59 | export DB_ID=$(shell uv run grype-db-manager db build --schema-version $(schema_version)) 60 | uv run grype-db-manager db validaate $(DB_ID) 61 | 62 | 63 | ## Halp! ################################# 64 | 65 | .PHONY: help 66 | help: 67 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}' 68 | -------------------------------------------------------------------------------- /manager/README.md: -------------------------------------------------------------------------------- 1 | # grype-db-manager 2 | 3 | A small python tool for publishing validated grype databases to S3 for distribution. 4 | 5 | This is a rough outline of the DB release process using this tool: 6 | 7 | ``` 8 | # build a new DB, validate it, and upload it to S3 9 | grype-db-manager -v db build-and-upload --schema-version # 10 | 11 | # recreate the DB listing file from the current S3 state and upload it 12 | # note: this requires having your AWS credentials configured 13 | grype-db-manager listing update 14 | ``` 15 | 16 | The configuration for grype-db-manager is stored at .grype-db-manager.yaml, and in the context of this repo, 17 | we have multiple configurations for different environments within the `config/grype-db-manager` directory. 18 | -------------------------------------------------------------------------------- /manager/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchore/grype-db/0f7a513850e355ffff3cb55ed5b05345ffb7ebd4/manager/__init__.py -------------------------------------------------------------------------------- /manager/src/grype_db_manager/__main__.py: -------------------------------------------------------------------------------- 1 | from grype_db_manager.cli import run 2 | 3 | run() 4 | -------------------------------------------------------------------------------- /manager/src/grype_db_manager/cli/__init__.py: -------------------------------------------------------------------------------- 1 | from .cli import cli 2 | 3 | 4 | def run() -> None: 5 | cli() 6 | -------------------------------------------------------------------------------- /manager/src/grype_db_manager/cli/error.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from functools import partial, wraps 4 | from typing import Any 5 | 6 | import click 7 | 8 | 9 | class CLIError(click.ClickException): 10 | def format_message(self) -> str: 11 | return click.style(self.message, fg="red") 12 | 13 | 14 | def handle_exception(func: callable = None, *, handle: Any | tuple[Any, ...]) -> callable: # noqa: RUF013 15 | if not func: 16 | return partial(handle_exception, handle=handle) 17 | 18 | @wraps(func) 19 | def wrapper(*args, **kwargs) -> Any: 20 | try: 21 | return func(*args, **kwargs) 22 | except handle as e: 23 | raise CLIError(e) from e 24 | 25 | return wrapper 26 | -------------------------------------------------------------------------------- /manager/src/grype_db_manager/cli/tool.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | import click 5 | from tabulate import tabulate 6 | 7 | from grype_db_manager.cli import config 8 | from grype_db_manager.grypedb import TOOLS_DIR, GrypeDB 9 | 10 | 11 | @click.group(name="tool", help="manage local grype-db installations") 12 | @click.pass_obj 13 | def group(_: config.Application) -> None: 14 | pass 15 | 16 | 17 | @group.command(name="list", help="list grype-db installations") 18 | @click.pass_obj 19 | def list_installed(cfg: config.Application) -> None: 20 | all_installations = GrypeDB.list_installed(root_dir=cfg.data.root) 21 | if not all_installations: 22 | click.echo("no grype-db installations found") 23 | return 24 | 25 | rows = [] 26 | for installation in all_installations: 27 | row = [installation.version] 28 | rows.append(row) 29 | 30 | click.echo_via_pager(tabulate(rows, tablefmt="plain")) 31 | 32 | 33 | @group.command(name="install", help="install grype-db at the configured version") 34 | @click.pass_obj 35 | def install(cfg: config.Application) -> None: 36 | GrypeDB.install(version=cfg.grype_db.version, root_dir=cfg.data.root) 37 | 38 | 39 | @group.command(name="clear", help="delete all grype-db installations") 40 | @click.pass_obj 41 | def clear(cfg: config.Application) -> None: 42 | # recursively delete the tools dir 43 | tools_dir = os.path.join(cfg.data.root, TOOLS_DIR) 44 | if os.path.exists(tools_dir): 45 | shutil.rmtree(tools_dir) 46 | click.echo("tools deleted") 47 | else: 48 | click.echo("no tools to clear") 49 | -------------------------------------------------------------------------------- /manager/src/grype_db_manager/data/schema-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "available":[ 3 | { 4 | "schema": "1", 5 | "grype-version": "v0.7.0", 6 | "supported": false 7 | }, 8 | { 9 | "schema": "2", 10 | "grype-version": "v0.12.1", 11 | "supported": false 12 | }, 13 | { 14 | "schema": "3", 15 | "grype-version": "v0.40.1", 16 | "supported": false 17 | }, 18 | { 19 | "schema": "4", 20 | "grype-version": "v0.50.2", 21 | "supported": false 22 | }, 23 | { 24 | "schema": "5", 25 | "grype-version": "v0.87.0", 26 | "supported": true 27 | }, 28 | { 29 | "schema": "6", 30 | "grype-version": "main", 31 | "supported": true 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /manager/src/grype_db_manager/db/__init__.py: -------------------------------------------------------------------------------- 1 | from . import listing, metadata, schema 2 | from .latest import Latest 3 | from .listing import Listing 4 | from .metadata import Metadata 5 | from .validation import capture_results 6 | 7 | __all__ = [ 8 | "Latest", 9 | "Listing", 10 | "Metadata", 11 | "capture_results", 12 | "latest", 13 | "listing", 14 | "metadata", 15 | "schema", 16 | ] 17 | -------------------------------------------------------------------------------- /manager/src/grype_db_manager/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import contextlib 4 | import functools 5 | import os 6 | import pathlib 7 | import subprocess 8 | from typing import TYPE_CHECKING 9 | 10 | if TYPE_CHECKING: 11 | from collections.abc import Iterable 12 | 13 | 14 | @functools.lru_cache(maxsize=1) 15 | def repo_root() -> str: 16 | try: 17 | base = subprocess.check_output("git rev-parse --show-toplevel", shell=True) # noqa: S607, S602 18 | except subprocess.CalledProcessError as e: 19 | msg = "Current working directory is not a git repository" 20 | raise OSError(msg) from e 21 | return base.decode("utf-8").strip() 22 | 23 | 24 | @contextlib.contextmanager 25 | def set_directory(path: pathlib.Path | str) -> Iterable[None]: 26 | origin = pathlib.Path().absolute() 27 | try: 28 | os.chdir(path) 29 | yield 30 | finally: 31 | os.chdir(origin) 32 | -------------------------------------------------------------------------------- /manager/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchore/grype-db/0f7a513850e355ffff3cb55ed5b05345ffb7ebd4/manager/tests/__init__.py -------------------------------------------------------------------------------- /manager/tests/cli/.gitignore: -------------------------------------------------------------------------------- 1 | cli-test-data* 2 | .yardstick 3 | .grype-db-manager 4 | grype-db-cache.tar.gz 5 | grype-db-cache.tar.zst 6 | venv 7 | bin -------------------------------------------------------------------------------- /manager/tests/cli/.grype-db.yaml: -------------------------------------------------------------------------------- 1 | # note: this file is not intended to be used for the daily-db-sync workflow to populate a vulnerability data cache 2 | 3 | provider: 4 | root: cli-test-data/vunnel 5 | 6 | configs: 7 | # let's use a limited set of providers that we can show in isolation the setup is generally working. We don't 8 | # need all providers / an entire database to test the workflow. 9 | - name: oracle 10 | kind: vunnel 11 | 12 | vunnel: 13 | executor: docker 14 | docker-tag: latest 15 | generate-configs: false 16 | 17 | pull: 18 | parallelism: 4 19 | 20 | package: 21 | publish-base-url: https://toolbox-data.anchore.io/grype/databases 22 | -------------------------------------------------------------------------------- /manager/tests/cli/.vunnel.yaml: -------------------------------------------------------------------------------- 1 | # note: this file is not intended to be used for the daily-db-sync workflow to populate a vulnerability data cache 2 | root: cli-test-data/vunnel 3 | 4 | log: 5 | slim: true 6 | level: debug 7 | 8 | providers: 9 | ubuntu: 10 | # there is a lot of IO when running git log commands in this provider, so some concurrency helps here 11 | max_workers: 10 12 | -------------------------------------------------------------------------------- /manager/tests/cli/.yardstick.yaml: -------------------------------------------------------------------------------- 1 | store-root: cli-test-data/yardstick -------------------------------------------------------------------------------- /manager/tests/cli/Makefile: -------------------------------------------------------------------------------- 1 | ACTIVATE_VENV = . venv/bin/activate && 2 | 3 | # formatting variables 4 | BOLD := $(shell tput -T linux bold)) 5 | CYAN := $(shell tput -T linux setaf 6) 6 | RESET := $(shell tput -T linux sgr0) 7 | 8 | test: ## Run CLI tests 9 | uv run pytest . -vv -o log_cli=true 10 | 11 | .PHONY: vunnel-oracle-data 12 | vunnel-oracle-data: cli-test-data/vunnel/oracle 13 | 14 | cli-test-data/vunnel/oracle: ## Prepare oracle data for CLI tests 15 | mkdir -p cli-test-data/vunnel 16 | ../../../.tool/oras pull ghcr.io/anchore/grype-db/data/oracle:latest && go run ../../../cmd/grype-db cache restore --path ./grype-db-cache.tar.gz 17 | 18 | .PHONY: install-oracle-labels 19 | install-oracle-labels: 20 | mkdir -p cli-test-data/yardstick/labels 21 | cp -a ../../../data/vulnerability-match-labels/labels/docker.io+oraclelinux* ./cli-test-data/yardstick/labels/ 22 | 23 | .PHONY: clean 24 | clean: clean-data ## Clear all existing yardstick results and delete python environment 25 | 26 | .PHONY: clean-data 27 | clean-data: clean-vunnel clean-yardstick clean-manager 28 | 29 | .PHONY: clean-vunnel 30 | clean-vunnel: 31 | rm -rf cli-test-data/vunnel 32 | 33 | .PHONY: clean-yardstick 34 | clean-yardstick: 35 | rm -rf cli-test-data/yardstick 36 | 37 | .PHONY: clean-yardstick-labels 38 | clean-yardstick-labels: 39 | rm -rf cli-test-data/yardstick/labels 40 | mkdir -p cli-test-data/yardstick/labels 41 | 42 | .PHONY: clean-manager 43 | clean-manager: 44 | rm -rf cli-test-data/manager 45 | 46 | help: 47 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}' -------------------------------------------------------------------------------- /manager/tests/cli/README.md: -------------------------------------------------------------------------------- 1 | # CLI tests 2 | 3 | The CLI tests here attempt to cover the most important user flows via the CLI, asserting correct return code, 4 | output to the terminal, and limited side effects (e.g. files created locally or uploaded to S3). 5 | 6 | Some tests rely on uploading files to S3, which has been mocked with a localstack instance via a docker compose stack. 7 | This means that no special AWS credentials or external S3 bucket / services are required for testing. 8 | 9 | If you want to run all CLI test: 10 | ```shell 11 | # from the manager/tests/cli directory 12 | 13 | make 14 | ``` 15 | 16 | If you'd like to run a single test: 17 | ```shell 18 | # from the manager/tests/cli directory 19 | 20 | pytest . -vv -o log_cli=true -k 21 | 22 | # e.g. 23 | # pytest . -vv -o log_cli=true -k test_workflow_4 24 | ``` 25 | -------------------------------------------------------------------------------- /manager/tests/cli/s3-mock/.gitignore: -------------------------------------------------------------------------------- 1 | /.localstack 2 | /.listing-cache -------------------------------------------------------------------------------- /manager/tests/cli/s3-mock/.grype-db-manager.yaml: -------------------------------------------------------------------------------- 1 | ../.grype-db-manager.yaml -------------------------------------------------------------------------------- /manager/tests/cli/s3-mock/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | localstack: 4 | image: localstack/localstack:2.2 5 | container_name: grype-db-manager-localstack 6 | ports: 7 | - '4563-4599:4563-4599' 8 | - '8055:8080' 9 | environment: 10 | - SERVICES=s3 11 | - DEBUG=0 12 | - DATA_DIR=/var/localstack/data 13 | volumes: 14 | - 'localstack:/var/localstack' 15 | - '/var/run/docker.sock:/var/run/docker.sock' 16 | 17 | volumes: 18 | localstack: 19 | 20 | -------------------------------------------------------------------------------- /manager/tests/cli/s3-mock/setup-legacy-workflow-4.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import shutil 4 | 5 | # the credentials are not required for localstack, but the boto3 client will complain if they are not set 6 | os.environ["AWS_ACCESS_KEY_ID"] = "test" 7 | os.environ["AWS_SECRET_ACCESS_KEY"] = "test" 8 | 9 | from grype_db_manager import s3utils, db 10 | from grype_db_manager.cli import config 11 | 12 | 13 | def main(): 14 | cfg = config.load() 15 | 16 | s3_bucket = cfg.distribution.s3_bucket 17 | s3_path = cfg.distribution.s3_path 18 | region = cfg.distribution.aws_region 19 | 20 | if not bucket_exists(s3_bucket): 21 | print(f"creating bucket {s3_bucket!r}") 22 | s3 = s3utils.ClientFactory.new() 23 | s3.create_bucket(Bucket=s3_bucket, CreateBucketConfiguration={"LocationConstraint": region}) 24 | 25 | print("uploading empty listing file") 26 | the_listing = db.listing.empty_listing() 27 | 28 | s3utils.upload(bucket=s3_bucket, key=f"{s3_path}/listing.json", contents=the_listing.to_json()) 29 | 30 | print("done!") 31 | 32 | 33 | def bucket_exists(bucket: str): 34 | try: 35 | list(s3utils.get_matching_s3_objects(bucket=bucket, prefix="")) 36 | return True 37 | except Exception as e: 38 | pass 39 | return False 40 | 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /manager/tests/cli/s3-mock/setup-workflow-1.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import shutil 4 | 5 | # the credentials are not required for localstack, but the boto3 client will complain if they are not set 6 | os.environ["AWS_ACCESS_KEY_ID"] = "test" 7 | os.environ["AWS_SECRET_ACCESS_KEY"] = "test" 8 | 9 | from grype_db_manager import s3utils 10 | from grype_db_manager.cli import config 11 | 12 | 13 | def main(): 14 | cfg = config.load() 15 | 16 | s3_bucket = cfg.distribution.s3_bucket 17 | region = cfg.distribution.aws_region 18 | 19 | if not bucket_exists(s3_bucket): 20 | print(f"creating bucket {s3_bucket!r}") 21 | s3 = s3utils.ClientFactory.new() 22 | s3.create_bucket(Bucket=s3_bucket, CreateBucketConfiguration={"LocationConstraint": region}) 23 | 24 | print("done!") 25 | 26 | 27 | def bucket_exists(bucket: str): 28 | try: 29 | list(s3utils.get_matching_s3_objects(bucket=bucket, prefix="")) 30 | return True 31 | except Exception as e: 32 | pass 33 | return False 34 | 35 | 36 | if __name__ == "__main__": 37 | main() 38 | -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/.gitignore: -------------------------------------------------------------------------------- 1 | # these test fixtures have no binary data contained in them 2 | !/**/*.tar.gz 3 | # this is not a real build dir 4 | !/**/build 5 | -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/README.md: -------------------------------------------------------------------------------- 1 | This is a grype-db-manager state directory with 2 DBs, schema versions 4 & 5. The DBs themselves are not present but the surrounding metadata is. -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/41e4c9e7-73c7-4106-bfb3-82e58ce15d9a/build/listing.json: -------------------------------------------------------------------------------- 1 | { 2 | "available": { 3 | "5": [ 4 | { 5 | "built": "2023-07-31T01:34:05Z", 6 | "version": 5, 7 | "url": "https://toolbox-data.anchore.io/grype/databases/vulnerability-db_v5_2023-07-31T01:34:05Z_36d351433b2adff2a5d8.tar.gz", 8 | "checksum": "sha256:cb787c5ad0447e5e942590078d23caf75a30345c57e4d5dea08a95f2f6e45dcd" 9 | } 10 | ] 11 | } 12 | } -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/41e4c9e7-73c7-4106-bfb3-82e58ce15d9a/build/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "built": "2023-07-31T01:34:05Z", 3 | "version": 5, 4 | "checksum": "sha256:c996a4c459a2fca9283c4fd8cdb53e3b050650d76e6ce517b91e34430f6db854" 5 | } -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/41e4c9e7-73c7-4106-bfb3-82e58ce15d9a/stage/vulnerability-db_v5_2023-08-03T01:34:34Z_54b7b6a76b058f1fa587.tar.gz: -------------------------------------------------------------------------------- 1 | dummy -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/41e4c9e7-73c7-4106-bfb3-82e58ce15d9a/timestamp: -------------------------------------------------------------------------------- 1 | 2023-07-31T03:45:08Z -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/9d1fce98-9c10-4887-949e-8296a259daf5/build/listing.json: -------------------------------------------------------------------------------- 1 | { 2 | "available": { 3 | "4": [ 4 | { 5 | "built": "2023-07-31T03:45:08Z", 6 | "version": 4, 7 | "url": "https://toolbox-data.anchore.io/grype/databases/vulnerability-db_v5_2023-07-31T03:45:08Z_36d351433b2adff2a5d8.tar.gz", 8 | "checksum": "sha256:e942590f2f6e45dcdc078d237e575a30345c57e4d5dea08a95af4cb787c5ad04" 9 | } 10 | ] 11 | } 12 | } -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/9d1fce98-9c10-4887-949e-8296a259daf5/build/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "built": "2023-07-30T03:45:08Z", 3 | "version": 4, 4 | "checksum": "sha256:0f2f6e45dcde94259c078d237e575a30787c5ad04345c57e4d5dea08a95af4cb" 5 | } 6 | -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/9d1fce98-9c10-4887-949e-8296a259daf5/stage/vulnerability-db_v4_2023-08-03T01:34:34Z_54b7b6a76b058f1fa587.tar.gz: -------------------------------------------------------------------------------- 1 | dummy -------------------------------------------------------------------------------- /manager/tests/fixtures/dbs-case-1/dbs/9d1fce98-9c10-4887-949e-8296a259daf5/timestamp: -------------------------------------------------------------------------------- 1 | 2023-07-30T03:45:08Z -------------------------------------------------------------------------------- /manager/tests/fixtures/tools-case-1/tools/grype-db/bin/grype-db-v0.18.0: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "grype-db v0.18.0" -------------------------------------------------------------------------------- /manager/tests/fixtures/tools-case-1/tools/grype-db/bin/grype-db-v0.19.0: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "grype-db v0.19.0" -------------------------------------------------------------------------------- /manager/tests/fixtures/tools-case-1/tools/grype-db/bin/grype-db-v0.19.0-2-gda1ca9e-dirty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "grype-db v0.19.0-2-gda1ca9e-dirty" -------------------------------------------------------------------------------- /manager/tests/fixtures/yardstick-sbom-result-set/effect/docker.io+ubuntu@sha256:aa6c2c047467afc828e77e306041b7fa4a65734fe3449a54aa9c280822b0d87d/syft@v0.74.1/2023-06-30T12:57:59.354289+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/ubuntu", "image_digest": "sha256:aa6c2c047467afc828e77e306041b7fa4a65734fe3449a54aa9c280822b0d87d", "tool_name": "syft", "tool_version": "v0.74.1", "image_tag": "22.04", "tool_input": null, "timestamp": "2023-06-30T12:57:59.354289+00:00", "detail": {}, "ID": "3ae4d03d-f04b-43eb-982c-8c2e1f966bad"}, "metadata": {"timestamp": "2023-06-30T12:57:59.354289+00:00", "elapsed": 4.05693, "image_digest": "sha256:aa6c2c047467afc828e77e306041b7fa4a65734fe3449a54aa9c280822b0d87d"}} -------------------------------------------------------------------------------- /manager/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchore/grype-db/0f7a513850e355ffff3cb55ed5b05345ffb7ebd4/manager/tests/unit/__init__.py -------------------------------------------------------------------------------- /manager/tests/unit/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchore/grype-db/0f7a513850e355ffff3cb55ed5b05345ffb7ebd4/manager/tests/unit/cli/__init__.py -------------------------------------------------------------------------------- /manager/tests/unit/cli/fixtures/config/full.yaml: -------------------------------------------------------------------------------- 1 | assertAwsCredentials: false 2 | 3 | data: 4 | root: data/manager 5 | vunnel-root: data/vunnel 6 | yardstick-root: data/yardstick 7 | 8 | grype-db: 9 | # use the current repo at the current commit as the source of truth for the grype-db build source. 10 | # note: assume this will be invoked from the root of the repo 11 | version: file://. 12 | 13 | # grype-db application configuration to use. 14 | # note: assume this will be invoked from the root of the repo 15 | config: config/grype-db-nightly-publisher.yaml 16 | 17 | distribution: 18 | listing-file-name: listing.json 19 | s3-path: grype/databases 20 | s3-bucket: testbucket 21 | aws-region: us-west-2 22 | s3-endpoint-url: http://localhost:4566 23 | download-url-prefix: http://localhost:4566/testbucket 24 | s3-always-suffix-schema-version: false 25 | listing_replicas: 26 | - awsRegion: us-west-2 27 | listingFileName: listing.json 28 | s3Bucket: testbucket 29 | s3Path: grype/databases 30 | 31 | schemaMappingFile: "mapping.json" 32 | 33 | validate: 34 | listing: 35 | image: "centos:8.2.2004" 36 | minimum-packages: 85 37 | minimum-vulnerabilities: 400 38 | 39 | default-max-year: 2021 40 | expectedProviders: 41 | - "alpine" 42 | gates: 43 | - gate: 44 | max_f1_regression: 0.15 45 | max_unlabeled_percent: 50 46 | max_new_false_negatives: 10 47 | max_year: 2021 48 | allow_empty_results_for_schemas: [1,2,3] 49 | images: 50 | - docker.io/cloudbees/cloudbees-core-agent:2.289.2.2@sha256:d48f0546b4cf5ef4626136242ce302f94a42751156b7be42f4b1b75a66608880 51 | verbosity: 2 -------------------------------------------------------------------------------- /manager/tests/unit/cli/fixtures/db/upload-test-config.yaml: -------------------------------------------------------------------------------- 1 | distribution: 2 | listing-file-name: listing.json 3 | s3-path: grype/databases 4 | # note: we are using localstack for testing, so the bucket name is arbitrary 5 | s3-bucket: testbucket 6 | aws-region: us-west-2 7 | s3-endpoint-url: http://localhost:4566 8 | -------------------------------------------------------------------------------- /manager/tests/unit/cli/fixtures/listing/create-all-exists/.grype-db-manager.yaml: -------------------------------------------------------------------------------- 1 | log: 2 | level: debug 3 | 4 | distribution: 5 | listing-file-name: listing.json 6 | s3-path: databases 7 | s3-bucket: testbucket 8 | aws-region: us-west-2 9 | download-url-prefix: http://localhost:4566/testbucket -------------------------------------------------------------------------------- /manager/tests/unit/cli/fixtures/listing/create-new-db/.grype-db-manager.yaml: -------------------------------------------------------------------------------- 1 | log: 2 | level: debug 3 | 4 | distribution: 5 | listing-file-name: listing.json 6 | s3-path: databases 7 | s3-bucket: testbucket 8 | aws-region: us-west-2 9 | download-url-prefix: http://localhost:4566/testbucket/ # assert that trailing / is trimmed 10 | -------------------------------------------------------------------------------- /manager/tests/unit/cli/test_db.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from click.testing import CliRunner 4 | 5 | from grype_db_manager import cli, grypedb 6 | 7 | 8 | def test_upload_db(mocker, test_dir_path, redact_aws_credentials): 9 | config_path = test_dir_path("fixtures/db/upload-test-config.yaml") 10 | 11 | # mock db.DBManager to return a mock object 12 | # the mock object should respond to get_db_info and return a grypedb.DBInfo object 13 | db_mock = mocker.patch("grype_db_manager.cli.db.DBManager") 14 | db_mock.return_value.get_db_info.return_value = grypedb.DBInfo( 15 | uuid="some-db-uuid", 16 | schema_version=5, 17 | db_checksum="checksum", 18 | db_created=datetime.datetime.now(), 19 | data_created=datetime.datetime.now(), 20 | archive_path="some/path/to/archive.tar.gz", 21 | ) 22 | 23 | s3_mock = mocker.patch("grype_db_manager.cli.db.s3utils") 24 | s3_mock.upload_file.return_value = None 25 | 26 | runner = CliRunner() 27 | result = runner.invoke(cli.cli, f"-c {config_path} db upload some-db-uuid".split()) 28 | 29 | assert result.exit_code == 0 30 | 31 | # ensure the s3 mock was called with the right arguments 32 | s3_mock.upload_file.assert_called_once_with( 33 | path="some/path/to/archive.tar.gz", 34 | bucket="testbucket", 35 | key="grype/databases/archive.tar.gz", 36 | CacheControl="public,max-age=31536000", 37 | ) 38 | -------------------------------------------------------------------------------- /manager/tests/unit/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchore/grype-db/0f7a513850e355ffff3cb55ed5b05345ffb7ebd4/manager/tests/unit/db/__init__.py -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/result-set-stale-detection/missing-result-set/result/sets/missing: -------------------------------------------------------------------------------- 1 | bogus -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/.yardstick.yaml: -------------------------------------------------------------------------------- 1 | store_root: yardstick -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/0e288c90-f8e5-4a9d-a768-d04d9876b831.json: -------------------------------------------------------------------------------- 1 | {"ID": "0e288c90-f8e5-4a9d-a768-d04d9876b831", "effective_cve": "CVE-2022-42898", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "krb5-libs", "version": "1.10.3-65.el6"}, "timestamp": "2023-08-07T14:54:57.349174", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12104"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/1cfae55e-4f8a-4d1e-b2ff-6ce962096299.json: -------------------------------------------------------------------------------- 1 | {"ID": "1cfae55e-4f8a-4d1e-b2ff-6ce962096299", "effective_cve": "CVE-2022-24407", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "cyrus-sasl-lib", "version": "2.1.23-15.el6_6.2"}, "timestamp": "2023-08-07T14:54:55.630001", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9239"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/2e30c6cd-cfcb-4fec-abfe-36cea35465cb.json: -------------------------------------------------------------------------------- 1 | {"ID": "2e30c6cd-cfcb-4fec-abfe-36cea35465cb", "effective_cve": "CVE-2022-24903", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "rsyslog", "version": "5.8.10-12.0.1.el6"}, "timestamp": "2023-08-07T14:54:59.839415", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9783"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/51332abc-47d5-4751-8776-ce69367b7201.json: -------------------------------------------------------------------------------- 1 | {"ID": "51332abc-47d5-4751-8776-ce69367b7201", "effective_cve": "CVE-2023-0767", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "nss-sysinit", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:58.195634", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12238"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/5ce7cadb-9c1b-4766-88d0-3a710544bc66.json: -------------------------------------------------------------------------------- 1 | {"ID": "5ce7cadb-9c1b-4766-88d0-3a710544bc66", "effective_cve": "CVE-2022-37434", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "zlib", "version": "1.2.3-29.el6"}, "timestamp": "2023-08-07T14:55:00.339866", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9988"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/726baa17-77da-49b9-857a-41cfc8474f94.json: -------------------------------------------------------------------------------- 1 | {"ID": "726baa17-77da-49b9-857a-41cfc8474f94", "effective_cve": "CVE-2018-25032", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "zlib", "version": "1.2.3-29.el6"}, "timestamp": "2023-08-07T14:55:00.070079", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9565"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/764afea8-909c-4cc1-a582-5f19eea73468.json: -------------------------------------------------------------------------------- 1 | {"ID": "764afea8-909c-4cc1-a582-5f19eea73468", "effective_cve": "CVE-2021-25217", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "dhcp-common", "version": "12:4.1.1-63.P1.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:56.543566", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9314"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/78318f73-ee3c-4956-be18-57a2cbb9fc10.json: -------------------------------------------------------------------------------- 1 | {"ID": "78318f73-ee3c-4956-be18-57a2cbb9fc10", "effective_cve": "CVE-2022-25235", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "expat", "version": "2.0.1-13.el6_8"}, "timestamp": "2023-08-07T14:54:56.737074", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9359"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/7bd80a83-13ae-407c-805c-678e21ce993b.json: -------------------------------------------------------------------------------- 1 | {"ID": "7bd80a83-13ae-407c-805c-678e21ce993b", "effective_cve": "CVE-2021-27219", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "glib2", "version": "2.28.8-10.el6"}, "timestamp": "2023-08-07T14:54:57.150518", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9318"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/89ebd842-6a70-4e64-b3a4-5243fd938dc4.json: -------------------------------------------------------------------------------- 1 | {"ID": "89ebd842-6a70-4e64-b3a4-5243fd938dc4", "effective_cve": "CVE-2021-43527", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "nss-tools", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:58.399728", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9591"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/91248621-e9ab-4372-9776-1fcccf40d177.json: -------------------------------------------------------------------------------- 1 | {"ID": "91248621-e9ab-4372-9776-1fcccf40d177", "effective_cve": "CVE-2021-43527", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "nss-sysinit", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:57.956848", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9591"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/9dad5945-f6bc-4294-8248-96e1c841edfe.json: -------------------------------------------------------------------------------- 1 | {"ID": "9dad5945-f6bc-4294-8248-96e1c841edfe", "effective_cve": "CVE-2021-25217", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "dhclient", "version": "12:4.1.1-63.P1.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:56.282409", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9314"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/9e3fbee0-fde6-49ab-8d93-9848f4f266dc.json: -------------------------------------------------------------------------------- 1 | {"ID": "9e3fbee0-fde6-49ab-8d93-9848f4f266dc", "effective_cve": "CVE-2023-0767", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "nss-tools", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:58.578817", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12238"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/b48e76c0-3619-490e-b601-59782d3c7c4e.json: -------------------------------------------------------------------------------- 1 | {"ID": "b48e76c0-3619-490e-b601-59782d3c7c4e", "effective_cve": "CVE-2022-40674", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "expat", "version": "2.0.1-13.el6_8"}, "timestamp": "2023-08-07T14:54:56.945237", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9962"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/ba20833c-8a08-49e2-8fb5-db7ac3398cb3.json: -------------------------------------------------------------------------------- 1 | {"ID": "ba20833c-8a08-49e2-8fb5-db7ac3398cb3", "effective_cve": "CVE-2022-0391", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "python-libs", "version": "2.6.6-68.0.2.el6_10"}, "timestamp": "2023-08-07T14:54:59.698595", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-3550"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/bb261f04-d5f8-4db1-937f-97db94879355.json: -------------------------------------------------------------------------------- 1 | {"ID": "bb261f04-d5f8-4db1-937f-97db94879355", "effective_cve": "CVE-2022-0391", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "python", "version": "2.6.6-68.0.2.el6_10"}, "timestamp": "2023-08-07T14:54:59.455076", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-3550"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/be8c414f-0ddc-4a4f-9e79-91923d3852c1.json: -------------------------------------------------------------------------------- 1 | {"ID": "be8c414f-0ddc-4a4f-9e79-91923d3852c1", "effective_cve": "CVE-2021-43527", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "nss", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:57.587223", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9591"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/cf5f84ad-9c80-48b0-be89-7d74f0f7d8dd.json: -------------------------------------------------------------------------------- 1 | {"ID": "cf5f84ad-9c80-48b0-be89-7d74f0f7d8dd", "effective_cve": "CVE-2022-0778", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "openssl", "version": "1.0.1e-58.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:58.999594", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9246"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/dd572e83-d184-4c2b-96b4-8d7ce32bfc6d.json: -------------------------------------------------------------------------------- 1 | {"ID": "dd572e83-d184-4c2b-96b4-8d7ce32bfc6d", "effective_cve": "CVE-2023-0767", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "nss", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:57.760017", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12238"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/ed124564-6e4d-4589-8c3d-638ce467a999.json: -------------------------------------------------------------------------------- 1 | {"ID": "ed124564-6e4d-4589-8c3d-638ce467a999", "effective_cve": "CVE-2020-1971", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "openssl", "version": "1.0.1e-58.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:58.795458", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9137"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/all-tp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/f0351994-014f-4140-a9a7-11d37998d66a.json: -------------------------------------------------------------------------------- 1 | {"ID": "f0351994-014f-4140-a9a7-11d37998d66a", "effective_cve": "CVE-2023-0286", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "openssl", "version": "1.0.1e-58.0.1.el6_10"}, "timestamp": "2023-08-07T14:54:59.216616", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12297"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/06bbb581-5f08-401c-9154-aebdbdb93888.json: -------------------------------------------------------------------------------- 1 | {"ID": "06bbb581-5f08-401c-9154-aebdbdb93888", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "openssl", "version": "1.0.1e-58.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:47.648655", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9137"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/0bf6b52b-0445-45a4-883a-033aa7ba30c3.json: -------------------------------------------------------------------------------- 1 | {"ID": "0bf6b52b-0445-45a4-883a-033aa7ba30c3", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "python-libs", "version": "2.6.6-68.0.2.el6_10"}, "timestamp": "2023-08-08T15:19:48.612576", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-3550"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/0f778a6f-a14e-4535-9338-15eb5bf608ac.json: -------------------------------------------------------------------------------- 1 | {"ID": "0f778a6f-a14e-4535-9338-15eb5bf608ac", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "dhcp-common", "version": "12:4.1.1-63.P1.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:43.782116", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9314"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/1a93ca64-31a9-48f7-b87b-33fef666c479.json: -------------------------------------------------------------------------------- 1 | {"ID": "1a93ca64-31a9-48f7-b87b-33fef666c479", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "dhclient", "version": "12:4.1.1-63.P1.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:43.524660", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9314"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/3875af9b-c820-444c-bdc4-26279badb612.json: -------------------------------------------------------------------------------- 1 | {"ID": "3875af9b-c820-444c-bdc4-26279badb612", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "glib2", "version": "2.28.8-10.el6"}, "timestamp": "2023-08-08T15:19:44.494824", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9318"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/3aeed8ef-eac4-44d0-a127-dbc5b9648c4d.json: -------------------------------------------------------------------------------- 1 | {"ID": "3aeed8ef-eac4-44d0-a127-dbc5b9648c4d", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "nss-sysinit", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:45.679471", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9591"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/48331d83-15cf-498b-8287-c8b93236088d.json: -------------------------------------------------------------------------------- 1 | {"ID": "48331d83-15cf-498b-8287-c8b93236088d", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "nss-sysinit", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:55.112036", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12238"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/4fcfaa8e-f98c-4269-a78f-8c0e4c159c3c.json: -------------------------------------------------------------------------------- 1 | {"ID": "4fcfaa8e-f98c-4269-a78f-8c0e4c159c3c", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "expat", "version": "2.0.1-13.el6_8"}, "timestamp": "2023-08-08T15:19:44.249406", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9962"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/5f997560-e5fc-4a0f-873b-1880355b6ebe.json: -------------------------------------------------------------------------------- 1 | {"ID": "5f997560-e5fc-4a0f-873b-1880355b6ebe", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "krb5-libs", "version": "1.10.3-65.el6"}, "timestamp": "2023-08-08T15:19:44.768023", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12104"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/6f5baf1a-858d-40b4-acab-b934bef7119d.json: -------------------------------------------------------------------------------- 1 | {"ID": "6f5baf1a-858d-40b4-acab-b934bef7119d", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "openssl", "version": "1.0.1e-58.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:47.877832", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9246"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/72e78828-082b-4ca3-b903-8879b15cc54d.json: -------------------------------------------------------------------------------- 1 | {"ID": "72e78828-082b-4ca3-b903-8879b15cc54d", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "nss-tools", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-08T15:30:10.480740", "tool": "grype@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9591"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/76189aae-a342-4612-91d2-5375b2c0767d.json: -------------------------------------------------------------------------------- 1 | {"ID": "76189aae-a342-4612-91d2-5375b2c0767d", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "python", "version": "2.6.6-68.0.2.el6_10"}, "timestamp": "2023-08-08T15:19:48.352067", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-3550"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/8f983ee0-c97c-477d-b5c8-2a463c447aaf.json: -------------------------------------------------------------------------------- 1 | {"ID": "8f983ee0-c97c-477d-b5c8-2a463c447aaf", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "nss", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:45.295185", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12238"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/a43a29b7-c2a9-41de-af13-27c7935f79b5.json: -------------------------------------------------------------------------------- 1 | {"ID": "a43a29b7-c2a9-41de-af13-27c7935f79b5", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "expat", "version": "2.0.1-13.el6_8"}, "timestamp": "2023-08-08T15:19:44.023009", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9359"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/bd2a4f1f-3e18-4bd6-b0b5-591e3331ca61.json: -------------------------------------------------------------------------------- 1 | {"ID": "bd2a4f1f-3e18-4bd6-b0b5-591e3331ca61", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "nss-tools", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-08T15:28:23.235544", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12238"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/d3f3ed73-6439-4b17-b65e-c45097465a9f.json: -------------------------------------------------------------------------------- 1 | {"ID": "d3f3ed73-6439-4b17-b65e-c45097465a9f", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "nss", "version": "3.44.0-7.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:45.028520", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2021-9591"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/d92ba7d3-3784-4908-8e97-61762388e0ee.json: -------------------------------------------------------------------------------- 1 | {"ID": "d92ba7d3-3784-4908-8e97-61762388e0ee", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "FP", "package": {"name": "cyrus-sasl-lib", "version": "2.1.23-15.el6_6.2"}, "timestamp": "2023-08-08T15:19:42.979279", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9239"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/dfcc3309-8832-4bc0-aa25-66c9af24b1fd.json: -------------------------------------------------------------------------------- 1 | {"ID": "dfcc3309-8832-4bc0-aa25-66c9af24b1fd", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "openssl", "version": "1.0.1e-58.0.1.el6_10"}, "timestamp": "2023-08-08T15:19:48.110115", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2023-12297"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/e5706ac8-e06d-46f8-a04f-32843ee56483.json: -------------------------------------------------------------------------------- 1 | {"ID": "e5706ac8-e06d-46f8-a04f-32843ee56483", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "rsyslog", "version": "5.8.10-12.0.1.el6"}, "timestamp": "2023-08-08T15:19:48.911087", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9783"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/e901d5b8-9462-45c2-8c0d-04a606425ddb.json: -------------------------------------------------------------------------------- 1 | {"ID": "e901d5b8-9462-45c2-8c0d-04a606425ddb", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "zlib", "version": "1.2.3-29.el6"}, "timestamp": "2023-08-08T15:19:49.200122", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9565"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/label-sets/first-half-fp/labels/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/f9495fc7-4e78-4923-85e6-048620ae460b.json: -------------------------------------------------------------------------------- 1 | {"ID": "f9495fc7-4e78-4923-85e6-048620ae460b", "image": {"exact": "docker.io/oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}, "label": "TP", "package": {"name": "zlib", "version": "1.2.3-29.el6"}, "timestamp": "2023-08-08T15:19:49.645690", "tool": "grype[custom-db]@v0.65.1", "user": "wagoodman", "vulnerability_id": "ELSA-2022-9988"} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/.gitignore: -------------------------------------------------------------------------------- 1 | /labels 2 | !metadata.json -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/grype@v0.65.1/2023-01-01T01:01:01.000001+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/oraclelinux", "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495", "tool_name": "grype", "tool_version": "v0.65.1", "image_tag": "6", "tool_input": "cli-test-data/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/syft@v0.86.1/2023-08-04T19:53:38.406034+00:00/data.json", "timestamp": "2023-01-01T01:01:01.000001+00:00", "detail": {"db": {"built": "2023-08-08T01:33:25Z", "schemaVersion": 5, "location": "cli-test-data/yardstick/tools/grype/v0.65.1/db/oss/5", "checksum": "sha256:20b0a31d433279802531567a21986e1c9b7fb5efd6bcf8cdbd3abd04f71ae35c", "error": null}}, "ID": "2008940b-917b-4927-94c3-2b64bfbabb5f"}, "metadata": {"timestamp": "2023-08-08T13:24:49.391262+00:00", "elapsed": 6.217, "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/grype@v0.65.1/2023-01-01T02:02:02.000002+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/oraclelinux", "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495", "tool_name": "grype", "tool_version": "v0.65.1", "image_tag": "6", "tool_input": "cli-test-data/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/syft@v0.86.1/2023-08-04T19:53:38.406034+00:00/data.json", "timestamp": "2023-01-01T02:02:02.000002+00:00", "detail": {"db": {"built": "2023-08-08T01:33:25Z", "schemaVersion": 5, "location": "cli-test-data/yardstick/tools/grype/v0.65.1/db/oss/5", "checksum": "sha256:20b0a31d433279802531567a21986e1c9b7fb5efd6bcf8cdbd3abd04f71ae35c", "error": null}}, "ID": "9400b208-791b-9247-4c93-4bffb2b6b5ab"}, "metadata": {"timestamp": "2023-08-08T13:24:49.391262+00:00", "elapsed": 6.217, "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/grype@v0.65.1/2023-01-01T03:03:03.000003+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/oraclelinux", "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495", "tool_name": "grype", "tool_version": "v0.65.1", "image_tag": "6", "tool_input": "cli-test-data/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/syft@v0.86.1/2023-08-04T19:53:38.406034+00:00/data.json", "timestamp": "2023-01-01T03:03:03.000003+00:00", "detail": {"db": {"built": "2023-08-08T01:33:25Z", "schemaVersion": 5, "location": "cli-test-data/yardstick/tools/grype/v0.65.1/db/oss/5", "checksum": "sha256:20b0a31d433279802531567a21986e1c9b7fb5efd6bcf8cdbd3abd04f71ae35c", "error": null}}, "ID": "009408b2-917b-2497-c943-4bfab2bfb6b5"}, "metadata": {"timestamp": "2023-08-08T13:24:49.391262+00:00", "elapsed": 6.217, "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/grype[custom-db]@v0.65.1/2023-02-02T01:01:01.000001+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/oraclelinux", "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495", "tool_name": "grype[custom-db]", "tool_version": "v0.65.1", "image_tag": "6", "tool_input": "cli-test-data/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/syft@v0.86.1/2023-08-04T19:53:38.406034+00:00/data.json", "timestamp": "2023-02-02T01:01:01.000001+00:00", "detail": {"version_detail": "v0.65.1", "db": {"built": "2023-08-08T01:33:25Z", "schemaVersion": 5, "location": "cli-test-data/yardstick/tools/grype[custom-db]/v0.65.1/db/sha256:d83c6ded81ea3ff69aad9b367b9daee5424b74f813a6d49e9e8ba15d210cbfb6/5", "checksum": "sha256:d83c6ded81ea3ff69aad9b367b9daee5424b74f813a6d49e9e8ba15d210cbfb6", "error": null}}, "ID": "e6314a1b-9f9f-49a0-9e13-d30b83effe87"}, "metadata": {"timestamp": "2023-08-08T13:24:48.119176+00:00", "elapsed": 4.62863, "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/grype[custom-db]@v0.65.1/2023-02-02T02:02:02.000002+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/oraclelinux", "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495", "tool_name": "grype[custom-db]", "tool_version": "v0.65.1", "image_tag": "6", "tool_input": "cli-test-data/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/syft@v0.86.1/2023-08-04T19:53:38.406034+00:00/data.json", "timestamp": "2023-02-02T02:02:02.000002+00:00", "detail": {"version_detail": "v0.65.1", "db": {"built": "2023-08-08T01:33:25Z", "schemaVersion": 5, "location": "cli-test-data/yardstick/tools/grype[custom-db]/v0.65.1/db/sha256:d83c6ded81ea3ff69aad9b367b9daee5424b74f813a6d49e9e8ba15d210cbfb6/5", "checksum": "sha256:d83c6ded81ea3ff69aad9b367b9daee5424b74f813a6d49e9e8ba15d210cbfb6", "error": null}}, "ID": "141be63a-99ff-a049-139e-b8dfe87303ef"}, "metadata": {"timestamp": "2023-08-08T13:24:48.119176+00:00", "elapsed": 4.62863, "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}} -------------------------------------------------------------------------------- /manager/tests/unit/db/fixtures/validate-image/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/grype[custom-db]@v0.65.1/2023-02-02T03:03:03.000003+00:00/metadata.json: -------------------------------------------------------------------------------- 1 | {"config": {"image_repo": "docker.io/oraclelinux", "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495", "tool_name": "grype[custom-db]", "tool_version": "v0.65.1", "image_tag": "6", "tool_input": "cli-test-data/yardstick/result/store/docker.io+oraclelinux@sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495/syft@v0.86.1/2023-08-04T19:53:38.406034+00:00/data.json", "timestamp": "2023-02-02T03:03:03.000003+00:00", "detail": {"version_detail": "v0.65.1", "db": {"built": "2023-08-08T01:33:25Z", "schemaVersion": 5, "location": "cli-test-data/yardstick/tools/grype[custom-db]/v0.65.1/db/sha256:d83c6ded81ea3ff69aad9b367b9daee5424b74f813a6d49e9e8ba15d210cbfb6/5", "checksum": "sha256:d83c6ded81ea3ff69aad9b367b9daee5424b74f813a6d49e9e8ba15d210cbfb6", "error": null}}, "ID": "1b13a4e6-9f9f-04a9-391e-ebf8d3ef8730"}, "metadata": {"timestamp": "2023-08-08T13:24:48.119176+00:00", "elapsed": 4.62863, "image_digest": "sha256:a06327c0f1d18d753f2a60bb17864c84a850bb6dcbcf5946dd1a8123f6e75495"}} -------------------------------------------------------------------------------- /manager/tests/unit/db/test_metadata.py: -------------------------------------------------------------------------------- 1 | from grype_db_manager.db import metadata 2 | 3 | 4 | def test_to_and_from_json(): 5 | subject = metadata.Metadata( 6 | built="2026-05-04T03:02:01Z", 7 | version=1, 8 | ) 9 | 10 | expected_to = '{"built": "2026-05-04T03:02:01Z", "version": 1}' 11 | 12 | got_to = subject.to_json() 13 | 14 | assert expected_to == got_to 15 | 16 | got_from = metadata.Metadata.from_json(got_to) 17 | 18 | assert subject == got_from 19 | -------------------------------------------------------------------------------- /manager/tests/unit/db/test_schema.py: -------------------------------------------------------------------------------- 1 | from grype_db_manager.db import schema 2 | 3 | 4 | def test_grype_version(): 5 | # str type 6 | assert "v0.7.0" == schema.grype_version("1") 7 | 8 | # all values 9 | assert "v0.7.0" == schema.grype_version(1) 10 | assert "v0.12.1" == schema.grype_version(2) 11 | assert "v0.40.1" == schema.grype_version(3) 12 | assert "v0.50.2" == schema.grype_version(4) 13 | assert "v0.87.0" == schema.grype_version(5) 14 | assert "main" == schema.grype_version(6) 15 | 16 | 17 | def test_supported_schema_versions(): 18 | assert schema.supported_schema_versions() == [5, 6] 19 | -------------------------------------------------------------------------------- /manager/tests/unit/fixtures/hash/target: -------------------------------------------------------------------------------- 1 | stuff! -------------------------------------------------------------------------------- /pkg/data/entry.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | // Entry is a data structure responsible for capturing an individual writable entry from a data.Processor (written by a data.Writer). 4 | type Entry struct { 5 | DBSchemaVersion int 6 | // Data is the specific payload that should be written (usually a grype-db v*.Entry struct) 7 | Data interface{} 8 | } 9 | -------------------------------------------------------------------------------- /pkg/data/processor.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/anchore/grype-db/pkg/provider" 7 | ) 8 | 9 | // Processor takes individual feed group cache files (for select feed groups) and is responsible to producing 10 | // data.Entry objects to be written to the DB. 11 | type Processor interface { 12 | IsSupported(schemaURL string) bool 13 | Process(reader io.Reader, state provider.State) ([]Entry, error) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/data/severity.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import "strings" 4 | 5 | type Severity string 6 | 7 | const ( 8 | SeverityUnknown Severity = "Unknown" 9 | SeverityNegligible Severity = "Negligible" 10 | SeverityLow Severity = "Low" 11 | SeverityMedium Severity = "Medium" 12 | SeverityHigh Severity = "High" 13 | SeverityCritical Severity = "Critical" 14 | ) 15 | 16 | func ParseSeverity(s string) Severity { 17 | clean := strings.TrimSpace(strings.ToLower(s)) 18 | switch clean { 19 | case "unknown", "": 20 | return SeverityUnknown 21 | case "negligible": 22 | return SeverityNegligible 23 | case "low": 24 | return SeverityLow 25 | case "medium": 26 | return SeverityMedium 27 | case "high": 28 | return SeverityHigh 29 | case "critical": 30 | return SeverityCritical 31 | default: 32 | return SeverityUnknown 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pkg/data/severity_test.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParseSeverity(t *testing.T) { 10 | tests := []struct { 11 | input string 12 | want Severity 13 | }{ 14 | { 15 | input: "negLIGible", 16 | want: SeverityNegligible, 17 | }, 18 | { 19 | input: "loW", 20 | want: SeverityLow, 21 | }, 22 | { 23 | input: "meDIum", 24 | want: SeverityMedium, 25 | }, 26 | { 27 | input: " hiGH", 28 | want: SeverityHigh, 29 | }, 30 | { 31 | input: "cRiTical ", 32 | want: SeverityCritical, 33 | }, 34 | { 35 | input: "unKNOWN", 36 | want: SeverityUnknown, 37 | }, 38 | { 39 | input: "", 40 | want: SeverityUnknown, 41 | }, 42 | { 43 | input: " ", 44 | want: SeverityUnknown, 45 | }, 46 | } 47 | for _, tt := range tests { 48 | t.Run(tt.input, func(t *testing.T) { 49 | assert.Equal(t, tt.want, ParseSeverity(tt.input)) 50 | }) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkg/data/transformers.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "github.com/anchore/grype-db/pkg/provider" 5 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 6 | ) 7 | 8 | // Transformers are functions that know how ta take individual data shapes defined in the unmarshal package and 9 | // reshape the data into data.Entry objects that are writable by a data.Writer. Transformers are dependency-injected 10 | // into commonly-shared data.Processors in the individual process.v* packages. 11 | 12 | // all v1 transformers (schema v1 - v5) 13 | 14 | type GitHubTransformer func(entry unmarshal.GitHubAdvisory) ([]Entry, error) 15 | type MSRCTransformer func(entry unmarshal.MSRCVulnerability) ([]Entry, error) 16 | type NVDTransformer func(entry unmarshal.NVDVulnerability) ([]Entry, error) 17 | type OSTransformer func(entry unmarshal.OSVulnerability) ([]Entry, error) 18 | type MatchExclusionTransformer func(entry unmarshal.MatchExclusion) ([]Entry, error) 19 | 20 | // all v2 transformers (schema v6+) 21 | type GitHubTransformerV2 func(entry unmarshal.GitHubAdvisory, state provider.State) ([]Entry, error) 22 | type MSRCTransformerV2 func(entry unmarshal.MSRCVulnerability, state provider.State) ([]Entry, error) 23 | type NVDTransformerV2 func(entry unmarshal.NVDVulnerability, state provider.State) ([]Entry, error) 24 | type OSTransformerV2 func(entry unmarshal.OSVulnerability, state provider.State) ([]Entry, error) 25 | type MatchExclusionTransformerV2 func(entry unmarshal.MatchExclusion, state provider.State) ([]Entry, error) 26 | 27 | type KnownExploitedVulnerabilityTransformerV2 func(entry unmarshal.KnownExploitedVulnerability, state provider.State) ([]Entry, error) 28 | type EPSSTransformerV2 func(entry unmarshal.EPSS, state provider.State) ([]Entry, error) 29 | type OSVTransformerV2 func(entry unmarshal.OSVVulnerability, state provider.State) ([]Entry, error) 30 | -------------------------------------------------------------------------------- /pkg/data/writer.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | // Writer knows how to persist one or more data.Entry objects to a database. Note that the backing implementations 4 | // may take advantage of bulk writes when possible (positively improving performance), which is why multiple 5 | // entries can be written at once. 6 | type Writer interface { 7 | Write(...Entry) error 8 | Close() error 9 | } 10 | -------------------------------------------------------------------------------- /pkg/event/event.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package event provides event types for all events that the library published onto the event bus. By convention, for each event 3 | defined here there should be a corresponding event parser defined in the parsers/ child package. 4 | */ 5 | package event 6 | 7 | import ( 8 | "github.com/wagoodman/go-partybus" 9 | 10 | "github.com/anchore/grype-db/internal" 11 | ) 12 | 13 | const ( 14 | prefix = internal.ApplicationName 15 | 16 | // Exit is a partybus event indicating the main process is to exit 17 | Exit partybus.EventType = prefix + "-exit-event" 18 | ) 19 | -------------------------------------------------------------------------------- /pkg/lib.go: -------------------------------------------------------------------------------- 1 | package pkg 2 | 3 | import ( 4 | "github.com/wagoodman/go-partybus" 5 | 6 | "github.com/anchore/go-logger" 7 | "github.com/anchore/grype-db/internal/bus" 8 | "github.com/anchore/grype-db/internal/log" 9 | ) 10 | 11 | func SetLogger(l logger.Logger) { 12 | log.Set(l) 13 | } 14 | 15 | func SetBus(b *partybus.Bus) { 16 | bus.SetPublisher(b) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/process/default_schema_version.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import grypeDB "github.com/anchore/grype/grype/db/v6" 4 | 5 | const DefaultSchemaVersion = grypeDB.ModelVersion 6 | -------------------------------------------------------------------------------- /pkg/process/generate.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | //go:generate go run ./internal/codename/generate/main.go 4 | -------------------------------------------------------------------------------- /pkg/process/internal/codename/codename.go: -------------------------------------------------------------------------------- 1 | package codename 2 | 3 | import "strings" 4 | 5 | func LookupOS(osName, majorVersion, minorVersion string) string { 6 | majorVersion = strings.TrimLeft(majorVersion, "0") 7 | if minorVersion != "0" { 8 | minorVersion = strings.TrimLeft(minorVersion, "0") 9 | } 10 | 11 | // try to find the most specific match (major and minor version) 12 | if versions, ok := normalizedOSCodenames[osName]; ok { 13 | if minorMap, ok := versions[majorVersion]; ok { 14 | if codename, ok := minorMap[minorVersion]; ok { 15 | return codename 16 | } 17 | // fall back to the least specific match (only major version, allowing for any minor version explicitly) 18 | if codename, ok := minorMap["*"]; ok { 19 | return codename 20 | } 21 | } 22 | } 23 | return "" 24 | } 25 | -------------------------------------------------------------------------------- /pkg/process/internal/common/clean_fixed_in_version.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "strings" 4 | 5 | func CleanFixedInVersion(version string) string { 6 | switch strings.TrimSpace(strings.ToLower(version)) { 7 | case "none", "": 8 | return "" 9 | default: 10 | return version 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pkg/process/internal/common/constraint.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | // match examples: 9 | // >= 5.0.0 10 | // <= 6.1.2.beta 11 | // >= 5.0.0 12 | // < 6.1 13 | // > 5.0.0 14 | // >=5 15 | // <6 16 | var forceSemVerPattern = regexp.MustCompile(`[><=]+\s*[^<>=]+`) 17 | 18 | func EnforceSemVerConstraint(constraint string) string { 19 | constraint = CleanConstraint(constraint) 20 | if constraint == "" { 21 | return "" 22 | } 23 | return strings.ReplaceAll(strings.Join(forceSemVerPattern.FindAllString(constraint, -1), ", "), " ", "") 24 | } 25 | 26 | func AndConstraints(c ...string) string { 27 | return strings.Join(c, " ") 28 | } 29 | 30 | func OrConstraints(c ...string) string { 31 | return strings.Join(c, " || ") 32 | } 33 | 34 | func CleanConstraint(constraint string) string { 35 | if strings.ToLower(constraint) == "none" { 36 | return "" 37 | } 38 | return constraint 39 | } 40 | -------------------------------------------------------------------------------- /pkg/process/internal/common/constraint_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "testing" 4 | 5 | func TestEnforceSemVerConstraint(t *testing.T) { 6 | tests := []struct { 7 | value string 8 | expected string 9 | }{ 10 | { 11 | value: " >= 5.0.0<7.1 ", 12 | expected: ">=5.0.0,<7.1", 13 | }, 14 | { 15 | value: "None", 16 | expected: "", 17 | }, 18 | { 19 | value: "", 20 | expected: "", 21 | }, 22 | } 23 | for _, test := range tests { 24 | t.Run(test.value, func(t *testing.T) { 25 | actual := EnforceSemVerConstraint(test.value) 26 | if actual != test.expected { 27 | t.Errorf("mismatch: '%s'!='%s'", actual, test.expected) 28 | } 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkg/process/internal/tests/utils.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | func CloseFile(f *os.File) { 9 | err := f.Close() 10 | 11 | if err != nil { 12 | log.Fatal("error closing file") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pkg/process/package.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | v6process "github.com/anchore/grype-db/pkg/process/v6" 8 | grypeDBLegacyDistribution "github.com/anchore/grype/grype/db/v5/distribution" 9 | ) 10 | 11 | func Package(dbDir, publishBaseURL, overrideArchiveExtension string) error { 12 | // check if metadata file exists, if so, then this 13 | if _, err := os.Stat(filepath.Join(dbDir, grypeDBLegacyDistribution.MetadataFileName)); os.IsNotExist(err) { 14 | // TODO: detect from disk which version of the DB is present 15 | return v6process.CreateArchive(dbDir, overrideArchiveExtension) 16 | } 17 | return packageLegacyDB(dbDir, publishBaseURL, overrideArchiveExtension) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/process/processors/epss_processor.go: -------------------------------------------------------------------------------- 1 | //nolint:dupl 2 | package processors 3 | 4 | import ( 5 | "io" 6 | 7 | "github.com/anchore/grype-db/internal/log" 8 | "github.com/anchore/grype-db/pkg/data" 9 | "github.com/anchore/grype-db/pkg/provider" 10 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 11 | ) 12 | 13 | type epssProcessor struct { 14 | transformer data.EPSSTransformerV2 15 | } 16 | 17 | func NewV2EPSSProcessor(transformer data.EPSSTransformerV2) data.Processor { 18 | return &epssProcessor{ 19 | transformer: transformer, 20 | } 21 | } 22 | 23 | func (p epssProcessor) Process(reader io.Reader, state provider.State) ([]data.Entry, error) { 24 | var results []data.Entry 25 | 26 | entries, err := unmarshal.EPSSEntries(reader) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | for _, entry := range entries { 32 | if entry.IsEmpty() { 33 | log.Warn("dropping empty EPSS entry") 34 | continue 35 | } 36 | 37 | transformedEntries, err := p.transformer(entry, state) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | results = append(results, transformedEntries...) 43 | } 44 | 45 | return results, nil 46 | } 47 | 48 | func (p epssProcessor) IsSupported(schemaURL string) bool { 49 | if !hasSchemaSegment(schemaURL, "epss") { 50 | return false 51 | } 52 | 53 | parsedVersion, err := parseVersion(schemaURL) 54 | if err != nil { 55 | log.WithFields("schema", schemaURL, "error", err).Error("failed to parse EPSS schema version") 56 | return false 57 | } 58 | 59 | return parsedVersion.Major == 1 60 | } 61 | -------------------------------------------------------------------------------- /pkg/process/processors/kev_processor.go: -------------------------------------------------------------------------------- 1 | //nolint:dupl 2 | package processors 3 | 4 | import ( 5 | "io" 6 | 7 | "github.com/anchore/grype-db/internal/log" 8 | "github.com/anchore/grype-db/pkg/data" 9 | "github.com/anchore/grype-db/pkg/provider" 10 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 11 | ) 12 | 13 | type kevProcessor struct { 14 | transformer data.KnownExploitedVulnerabilityTransformerV2 15 | } 16 | 17 | func NewV2KEVProcessor(transformer data.KnownExploitedVulnerabilityTransformerV2) data.Processor { 18 | return &kevProcessor{ 19 | transformer: transformer, 20 | } 21 | } 22 | 23 | func (p kevProcessor) Process(reader io.Reader, state provider.State) ([]data.Entry, error) { 24 | var results []data.Entry 25 | 26 | entries, err := unmarshal.KnownExploitedVulnerabilityEntries(reader) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | for _, entry := range entries { 32 | if entry.IsEmpty() { 33 | log.Warn("dropping empty KEV entry") 34 | continue 35 | } 36 | 37 | transformedEntries, err := p.transformer(entry, state) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | results = append(results, transformedEntries...) 43 | } 44 | 45 | return results, nil 46 | } 47 | 48 | func (p kevProcessor) IsSupported(schemaURL string) bool { 49 | if !hasSchemaSegment(schemaURL, "known-exploited") { 50 | return false 51 | } 52 | 53 | parsedVersion, err := parseVersion(schemaURL) 54 | if err != nil { 55 | log.WithFields("schema", schemaURL, "error", err).Error("failed to parse KEV schema version") 56 | return false 57 | } 58 | 59 | return parsedVersion.Major == 1 60 | } 61 | -------------------------------------------------------------------------------- /pkg/process/processors/match_exclusion_processor.go: -------------------------------------------------------------------------------- 1 | //nolint:dupl 2 | package processors 3 | 4 | import ( 5 | "io" 6 | 7 | "github.com/anchore/grype-db/internal/log" 8 | "github.com/anchore/grype-db/pkg/data" 9 | "github.com/anchore/grype-db/pkg/provider" 10 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 11 | ) 12 | 13 | type matchExclusionProcessor struct { 14 | transformer data.MatchExclusionTransformer 15 | } 16 | 17 | func NewMatchExclusionProcessor(transformer data.MatchExclusionTransformer) data.Processor { 18 | return &matchExclusionProcessor{ 19 | transformer: transformer, 20 | } 21 | } 22 | 23 | func (p matchExclusionProcessor) Process(reader io.Reader, _ provider.State) ([]data.Entry, error) { 24 | var results []data.Entry 25 | 26 | entries, err := unmarshal.MatchExclusions(reader) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | for _, entry := range entries { 32 | if entry.IsEmpty() { 33 | log.Warn("dropping empty match-exclusion entry") 34 | continue 35 | } 36 | 37 | transformedEntries, err := p.transformer(entry) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | results = append(results, transformedEntries...) 43 | } 44 | 45 | return results, nil 46 | } 47 | 48 | func (p matchExclusionProcessor) IsSupported(schemaURL string) bool { 49 | if !hasSchemaSegment(schemaURL, "match-exclusion") { 50 | return false 51 | } 52 | 53 | parsedVersion, err := parseVersion(schemaURL) 54 | if err != nil { 55 | log.WithFields("schema", schemaURL, "error", err).Error("failed to parse match-exclusion schema version") 56 | return false 57 | } 58 | 59 | return parsedVersion.Major == 1 60 | } 61 | -------------------------------------------------------------------------------- /pkg/process/processors/osv_processor.go: -------------------------------------------------------------------------------- 1 | package processors 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/anchore/grype-db/internal/log" 7 | "github.com/anchore/grype-db/pkg/data" 8 | "github.com/anchore/grype-db/pkg/provider" 9 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 10 | ) 11 | 12 | type osvProcessor struct { 13 | transformer data.OSVTransformerV2 14 | } 15 | 16 | func NewV2OSVProcessor(transformer data.OSVTransformerV2) data.Processor { 17 | return &osvProcessor{ 18 | transformer: transformer, 19 | } 20 | } 21 | 22 | func (p osvProcessor) Process(reader io.Reader, state provider.State) ([]data.Entry, error) { 23 | var results []data.Entry 24 | 25 | entries, err := unmarshal.OSVVulnerabilityEntries(reader) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | for _, entry := range entries { 31 | transformedEntries, err := p.transformer(entry, state) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | results = append(results, transformedEntries...) 37 | } 38 | 39 | return results, nil 40 | } 41 | 42 | func (p osvProcessor) IsSupported(schemaURL string) bool { 43 | if !hasSchemaSegment(schemaURL, "osv") { 44 | return false 45 | } 46 | 47 | parsedVersion, err := parseVersion(schemaURL) 48 | if err != nil { 49 | log.WithFields("schema", schemaURL, "error", err).Error("failed to parse NVD schema version") 50 | return false 51 | } 52 | 53 | return parsedVersion.Major == 1 54 | } 55 | -------------------------------------------------------------------------------- /pkg/process/processors/test-fixtures/epss.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "cve": "CVE-2025-0108", 4 | "epss": 0.328, 5 | "percentile": 0.9929, 6 | "date": "2025-02-18" 7 | }, 8 | { 9 | "cve": "CVE-2025-0109", 10 | "epss": 0.283, 11 | "percentile": 0.9297, 12 | "date": "2025-02-18" 13 | } 14 | ] -------------------------------------------------------------------------------- /pkg/process/processors/test-fixtures/exclusions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | }, 4 | { 5 | "id": "CVE-1234-5678", 6 | "justification": "CVE-1234-5678 is imaginary" 7 | }, 8 | { 9 | "id": "CVE-2012-abcxyz", 10 | "constraints": [ 11 | { 12 | "namespaces": [ 13 | "nvd:cpe", 14 | "abc.xyz:python" 15 | ] 16 | } 17 | ], 18 | "justification": "some reason" 19 | }, 20 | { 21 | "id": "CVE-2015-abc123", 22 | "constraints": [ 23 | { 24 | "ecosystem_constraints": [ 25 | { 26 | "language": "python", 27 | "package_constraints": [ 28 | { 29 | "package_name": "clock" 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ], 36 | "justification": "" 37 | } 38 | ] -------------------------------------------------------------------------------- /pkg/process/processors/version.go: -------------------------------------------------------------------------------- 1 | package processors 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | var schemaFilePattern = regexp.MustCompile(`schema-(?P\d+)\.(?P\d+)\.(?P\d+)\.json`) 11 | 12 | type version struct { 13 | Major int 14 | Minor int 15 | Patch int 16 | } 17 | 18 | func parseVersion(schemaURL string) (*version, error) { 19 | matches := schemaFilePattern.FindStringSubmatch(schemaURL) 20 | if matches == nil { 21 | return nil, fmt.Errorf("invalid version format in URL: %s", schemaURL) 22 | } 23 | 24 | v := &version{} 25 | for i, name := range schemaFilePattern.SubexpNames() { 26 | if name == "" { 27 | continue 28 | } 29 | value, err := strconv.Atoi(matches[i]) 30 | if err != nil { 31 | return nil, fmt.Errorf("failed to parse %s: %v", name, err) 32 | } 33 | switch name { 34 | case "major": 35 | v.Major = value 36 | case "minor": 37 | v.Minor = value 38 | case "patch": 39 | v.Patch = value 40 | } 41 | } 42 | 43 | return v, nil 44 | } 45 | 46 | func hasSchemaSegment(schemaURL string, segment string) bool { 47 | return strings.Contains(schemaURL, "/"+segment+"/") 48 | } 49 | -------------------------------------------------------------------------------- /pkg/process/processors/version_test.go: -------------------------------------------------------------------------------- 1 | package processors 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParseVersion(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | schemaURL string 13 | expected *version 14 | wantErr bool 15 | }{ 16 | { 17 | name: "valid version 1.0.0", 18 | schemaURL: "https://example.com/vunnel/path/schema-1.0.0.json", 19 | expected: &version{Major: 1, Minor: 0, Patch: 0}, 20 | wantErr: false, 21 | }, 22 | { 23 | name: "valid version 2.3.4", 24 | schemaURL: "https://example.com/vunnel/path/schema-2.3.4.json", 25 | expected: &version{Major: 2, Minor: 3, Patch: 4}, 26 | wantErr: false, 27 | }, 28 | { 29 | name: "missing patch version", 30 | schemaURL: "https://example.com/vunnel/path/schema-1.0.json", 31 | expected: nil, 32 | wantErr: true, 33 | }, 34 | { 35 | name: "invalid format", 36 | schemaURL: "https://example.com/vunnel/path/schema.json", 37 | expected: nil, 38 | wantErr: true, 39 | }, 40 | { 41 | name: "non-numeric version", 42 | schemaURL: "https://example.com/vunnel/path/schema-1.a.0.json", 43 | expected: nil, 44 | wantErr: true, 45 | }, 46 | { 47 | name: "valid version with extra path", 48 | schemaURL: "https://example.com/vunnel/path/vulnerability/schema-1.2.3.json", 49 | expected: &version{Major: 1, Minor: 2, Patch: 3}, 50 | wantErr: false, 51 | }, 52 | } 53 | 54 | for _, tt := range tests { 55 | t.Run(tt.name, func(t *testing.T) { 56 | result, err := parseVersion(tt.schemaURL) 57 | if tt.wantErr { 58 | assert.Error(t, err) 59 | assert.Nil(t, result) 60 | } else { 61 | assert.NoError(t, err) 62 | assert.Equal(t, tt.expected, result) 63 | } 64 | }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/process/v5/processors.go: -------------------------------------------------------------------------------- 1 | package v5 2 | 3 | import ( 4 | "github.com/scylladb/go-set/strset" 5 | 6 | "github.com/anchore/grype-db/pkg/data" 7 | "github.com/anchore/grype-db/pkg/process/processors" 8 | "github.com/anchore/grype-db/pkg/process/v5/transformers/github" 9 | "github.com/anchore/grype-db/pkg/process/v5/transformers/matchexclusions" 10 | "github.com/anchore/grype-db/pkg/process/v5/transformers/msrc" 11 | "github.com/anchore/grype-db/pkg/process/v5/transformers/nvd" 12 | "github.com/anchore/grype-db/pkg/process/v5/transformers/os" 13 | ) 14 | 15 | type Config struct { 16 | NVD nvd.Config 17 | } 18 | 19 | type Option func(cfg *Config) 20 | 21 | func WithCPEParts(included []string) Option { 22 | return func(cfg *Config) { 23 | cfg.NVD.CPEParts = strset.New(included...) 24 | } 25 | } 26 | 27 | func WithInferNVDFixVersions(infer bool) Option { 28 | return func(cfg *Config) { 29 | cfg.NVD.InferNVDFixVersions = infer 30 | } 31 | } 32 | 33 | func NewConfig(options ...Option) Config { 34 | var cfg Config 35 | for _, option := range options { 36 | option(&cfg) 37 | } 38 | 39 | return cfg 40 | } 41 | 42 | func Processors(cfg Config) []data.Processor { 43 | return []data.Processor{ 44 | processors.NewGitHubProcessor(github.Transform), 45 | processors.NewMSRCProcessor(msrc.Transform), 46 | processors.NewNVDProcessor(nvd.Transformer(cfg.NVD)), 47 | processors.NewOSProcessor(os.Transform), 48 | processors.NewMatchExclusionProcessor(matchexclusions.Transform), 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/entry.go: -------------------------------------------------------------------------------- 1 | package transformers 2 | 3 | import ( 4 | "github.com/anchore/grype-db/pkg/data" 5 | grypeDB "github.com/anchore/grype/grype/db/v5" 6 | ) 7 | 8 | func NewEntries(vs []grypeDB.Vulnerability, metadata grypeDB.VulnerabilityMetadata) []data.Entry { 9 | entries := []data.Entry{ 10 | { 11 | DBSchemaVersion: grypeDB.SchemaVersion, 12 | Data: metadata, 13 | }, 14 | } 15 | for _, vuln := range vs { 16 | entries = append(entries, data.Entry{ 17 | DBSchemaVersion: grypeDB.SchemaVersion, 18 | Data: vuln, 19 | }) 20 | } 21 | return entries 22 | } 23 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/github/test-fixtures/github-github-npm-0.json: -------------------------------------------------------------------------------- 1 | { 2 | "Advisory": { 3 | "Classification": "GENERAL", 4 | "Severity": "Critical", 5 | "CVSS": { 6 | "version": "3.1", 7 | "vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 8 | "base_metrics": { 9 | "base_score": 9.8, 10 | "exploitability_score": 3.9, 11 | "impact_score": 5.9, 12 | "base_severity": "Critical" 13 | }, 14 | "status": "N/A" 15 | }, 16 | "FixedIn": [ 17 | { 18 | "name": "scratch-vm", 19 | "identifier": "0.2.0-prerelease.20200714185213", 20 | "ecosystem": "npm", 21 | "namespace": "github:npm", 22 | "range": "<= 0.2.0-prerelease.20200709173451" 23 | } 24 | ], 25 | "Summary": "Remote Code Execution in scratch-vm", 26 | "url": "https://github.com/advisories/GHSA-vc9j-fhvv-8vrf", 27 | "CVE": [ 28 | "CVE-2020-14000" 29 | ], 30 | "Metadata": { 31 | "CVE": [ 32 | "CVE-2020-14000" 33 | ] 34 | }, 35 | "ghsaId": "GHSA-vc9j-fhvv-8vrf", 36 | "published": "2020-07-27T19:55:52Z", 37 | "updated": "2023-01-09T05:03:39Z", 38 | "withdrawn": null, 39 | "namespace": "github:npm" 40 | } 41 | } -------------------------------------------------------------------------------- /pkg/process/v5/transformers/github/test-fixtures/github-github-python-0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2018-8768" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "5.4.1", 11 | "name": "notebook", 12 | "namespace": "github:python", 13 | "range": "< 5.4.1" 14 | } 15 | ], 16 | "Metadata": { 17 | "CVE": [ 18 | "CVE-2018-8768" 19 | ] 20 | }, 21 | "Severity": "Low", 22 | "Summary": "Low severity vulnerability that affects notebook", 23 | "ghsaId": "GHSA-6cwv-x26c-w2q4", 24 | "namespace": "github:python", 25 | "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", 26 | "withdrawn": null 27 | }, 28 | "Vulnerability": {} 29 | }, 30 | { 31 | "Advisory": { 32 | "CVE": [ 33 | "CVE-2017-5524" 34 | ], 35 | "FixedIn": [ 36 | { 37 | "ecosystem": "python", 38 | "identifier": "4.3.12", 39 | "name": "Plone", 40 | "namespace": "github:python", 41 | "range": ">= 4.0 < 4.3.12" 42 | } 43 | ], 44 | "Metadata": { 45 | "CVE": [ 46 | "CVE-2017-5524" 47 | ] 48 | }, 49 | "Severity": "Medium", 50 | "Summary": "Moderate severity vulnerability that affects Plone", 51 | "ghsaId": "GHSA-p5wr-vp8g-q5p4", 52 | "namespace": "github:python", 53 | "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", 54 | "withdrawn": null 55 | }, 56 | "Vulnerability": {} 57 | } 58 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/github/test-fixtures/github-github-python-1.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2017-5524" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "4.3.12", 11 | "name": "Plone", 12 | "namespace": "github:python", 13 | "range": ">= 4.0 < 4.3.12" 14 | }, 15 | { 16 | "ecosystem": "python", 17 | "identifier": "5.1b1", 18 | "name": "Plone", 19 | "namespace": "github:python", 20 | "range": ">= 5.1a1 < 5.1b1" 21 | }, 22 | { 23 | "ecosystem": "python", 24 | "identifier": "5.0.7", 25 | "name": "Plone", 26 | "namespace": "github:python", 27 | "range": ">= 5.0rc1 < 5.0.7" 28 | } 29 | ], 30 | "Metadata": { 31 | "CVE": [ 32 | "CVE-2017-5524" 33 | ] 34 | }, 35 | "Severity": "Medium", 36 | "Summary": "Moderate severity vulnerability that affects Plone", 37 | "ghsaId": "GHSA-p5wr-vp8g-q5p4", 38 | "namespace": "github:python", 39 | "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", 40 | "withdrawn": null 41 | }, 42 | "Vulnerability": {} 43 | } 44 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/github/test-fixtures/github-withdrawn.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2018-8768" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "5.4.1", 11 | "name": "notebook", 12 | "namespace": "github:python", 13 | "range": "< 5.4.1" 14 | } 15 | ], 16 | "Metadata": { 17 | "CVE": [ 18 | "CVE-2018-8768" 19 | ] 20 | }, 21 | "Severity": "Low", 22 | "Summary": "Low severity vulnerability that affects notebook", 23 | "ghsaId": "GHSA-6cwv-x26c-w2q4", 24 | "namespace": "github:python", 25 | "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", 26 | "withdrawn": "2022-01-31T14:32:09Z" 27 | }, 28 | "Vulnerability": {} 29 | } 30 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/github/test-fixtures/multiple-fixed-in-names.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2017-5524" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "4.3.12", 11 | "name": "Plone", 12 | "namespace": "github:python", 13 | "range": ">= 4.0 < 4.3.12" 14 | }, 15 | { 16 | "ecosystem": "python", 17 | "identifier": "5.1b1", 18 | "name": "Plone", 19 | "namespace": "github:python", 20 | "range": ">= 5.1a1 < 5.1b1" 21 | }, 22 | { 23 | "ecosystem": "python", 24 | "identifier": "5.0.7", 25 | "name": "Plone-debug", 26 | "namespace": "github:python", 27 | "range": ">= 5.0rc1 < 5.0.7" 28 | } 29 | ], 30 | "Metadata": { 31 | "CVE": [ 32 | "CVE-2017-5524" 33 | ] 34 | }, 35 | "Severity": "Medium", 36 | "Summary": "Moderate severity vulnerability that affects Plone", 37 | "ghsaId": "GHSA-p5wr-vp8g-q5p4", 38 | "namespace": "github:python", 39 | "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", 40 | "withdrawn": null 41 | }, 42 | "Vulnerability": {} 43 | } 44 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/matchexclusions/transform.go: -------------------------------------------------------------------------------- 1 | package matchexclusions 2 | 3 | import ( 4 | "github.com/anchore/grype-db/pkg/data" 5 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 6 | grypeDB "github.com/anchore/grype/grype/db/v5" 7 | ) 8 | 9 | func Transform(matchExclusion unmarshal.MatchExclusion) ([]data.Entry, error) { 10 | exclusion := grypeDB.VulnerabilityMatchExclusion{ 11 | ID: matchExclusion.ID, 12 | Constraints: nil, 13 | Justification: matchExclusion.Justification, 14 | } 15 | 16 | for _, c := range matchExclusion.Constraints { 17 | constraint := &grypeDB.VulnerabilityMatchExclusionConstraint{ 18 | Vulnerability: grypeDB.VulnerabilityExclusionConstraint{ 19 | Namespace: c.Vulnerability.Namespace, 20 | FixState: grypeDB.FixState(c.Vulnerability.FixState), 21 | }, 22 | Package: grypeDB.PackageExclusionConstraint{ 23 | Name: c.Package.Name, 24 | Language: c.Package.Language, 25 | Type: c.Package.Type, 26 | Version: c.Package.Version, 27 | Location: c.Package.Location, 28 | }, 29 | } 30 | 31 | exclusion.Constraints = append(exclusion.Constraints, *constraint) 32 | } 33 | 34 | entries := []data.Entry{ 35 | { 36 | DBSchemaVersion: grypeDB.SchemaVersion, 37 | Data: exclusion, 38 | }, 39 | } 40 | 41 | return entries, nil 42 | } 43 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/nvd/unique_pkg_tracker.go: -------------------------------------------------------------------------------- 1 | package nvd 2 | 3 | import ( 4 | "sort" 5 | 6 | "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" 7 | ) 8 | 9 | type uniquePkgTracker map[pkgCandidate][]nvd.CpeMatch 10 | 11 | func newUniquePkgTracker() uniquePkgTracker { 12 | return make(uniquePkgTracker) 13 | } 14 | 15 | func (s uniquePkgTracker) Diff(other uniquePkgTracker) (missing []pkgCandidate, extra []pkgCandidate) { 16 | for k := range s { 17 | if !other.Contains(k) { 18 | missing = append(missing, k) 19 | } 20 | } 21 | 22 | for k := range other { 23 | if !s.Contains(k) { 24 | extra = append(extra, k) 25 | } 26 | } 27 | 28 | return 29 | } 30 | 31 | func (s uniquePkgTracker) Matches(i pkgCandidate) []nvd.CpeMatch { 32 | return s[i] 33 | } 34 | 35 | func (s uniquePkgTracker) Add(i pkgCandidate, match nvd.CpeMatch) { 36 | if _, ok := s[i]; !ok { 37 | s[i] = make([]nvd.CpeMatch, 0) 38 | } 39 | s[i] = append(s[i], match) 40 | } 41 | 42 | func (s uniquePkgTracker) Remove(i pkgCandidate) { 43 | delete(s, i) 44 | } 45 | 46 | func (s uniquePkgTracker) Contains(i pkgCandidate) bool { 47 | _, ok := s[i] 48 | return ok 49 | } 50 | 51 | func (s uniquePkgTracker) All() []pkgCandidate { 52 | res := make([]pkgCandidate, len(s)) 53 | idx := 0 54 | for k := range s { 55 | res[idx] = k 56 | idx++ 57 | } 58 | 59 | sort.SliceStable(res, func(i, j int) bool { 60 | return res[i].String() < res[j].String() 61 | }) 62 | 63 | return res 64 | } 65 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/alpine-3.9.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "xen", 9 | "NamespaceName": "alpine:3.9", 10 | "Version": "4.11.1-r0", 11 | "VersionFormat": "apk" 12 | } 13 | ], 14 | "Link": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967", 15 | "Metadata": { 16 | "NVD": { 17 | "CVSSv2": { 18 | "Score": 4.9, 19 | "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:C" 20 | } 21 | } 22 | }, 23 | "Name": "CVE-2018-19967", 24 | "NamespaceName": "alpine:3.9", 25 | "Severity": "Medium" 26 | } 27 | } 28 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/amzn.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Description": "", 5 | "FixedIn": [ 6 | { 7 | "Name": "389-ds-base", 8 | "NamespaceName": "amzn:2", 9 | "Version": "1.3.8.4-15.amzn2.0.1", 10 | "VersionFormat": "rpm" 11 | }, 12 | { 13 | "Name": "389-ds-base-debuginfo", 14 | "NamespaceName": "amzn:2", 15 | "Version": "1.3.8.4-15.amzn2.0.1", 16 | "VersionFormat": "rpm" 17 | }, 18 | { 19 | "Name": "389-ds-base-devel", 20 | "NamespaceName": "amzn:2", 21 | "Version": "1.3.8.4-15.amzn2.0.1", 22 | "VersionFormat": "rpm" 23 | }, 24 | { 25 | "Name": "389-ds-base-libs", 26 | "NamespaceName": "amzn:2", 27 | "Version": "1.3.8.4-15.amzn2.0.1", 28 | "VersionFormat": "rpm" 29 | }, 30 | { 31 | "Name": "389-ds-base-snmp", 32 | "NamespaceName": "amzn:2", 33 | "Version": "1.3.8.4-15.amzn2.0.1", 34 | "VersionFormat": "rpm" 35 | } 36 | ], 37 | "Link": "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", 38 | "Metadata": { 39 | "CVE": [ 40 | { 41 | "Name": "CVE-2018-14648" 42 | } 43 | ] 44 | }, 45 | "Name": "ALAS-2018-1106", 46 | "NamespaceName": "amzn:2", 47 | "Severity": "Medium" 48 | } 49 | } 50 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/azure-linux-3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Name": "CVE-2023-29403", 5 | "NamespaceName": "mariner:3.0", 6 | "Description": "CVE-2023-29403 affecting package golang for versions less than 1.20.7-1. A patched version of the package is available.", 7 | "Severity": "High", 8 | "Link": "https://nvd.nist.gov/vuln/detail/CVE-2023-29403", 9 | "CVSS": [], 10 | "FixedIn": [ 11 | { 12 | "Name": "golang", 13 | "NamespaceName": "mariner:3.0", 14 | "VersionFormat": "rpm", 15 | "Version": "0:1.20.7-1.azl3", 16 | "Module": "", 17 | "VendorAdvisory": { 18 | "NoAdvisory": false, 19 | "AdvisorySummary": [] 20 | } 21 | } 22 | ], 23 | "Metadata": {} 24 | } 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "rsyslog", 9 | "NamespaceName": "debian:8", 10 | "VendorAdvisory": { 11 | "AdvisorySummary": [], 12 | "NoAdvisory": false 13 | }, 14 | "Version": "5.7.4-1", 15 | "VersionFormat": "dpkg" 16 | } 17 | ], 18 | "Link": "https://security-tracker.debian.org/tracker/CVE-2011-4623", 19 | "Metadata": { 20 | "NVD": { 21 | "CVSSv2": { 22 | "Score": 2.1, 23 | "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:P" 24 | } 25 | } 26 | }, 27 | "Name": "CVE-2011-4623", 28 | "NamespaceName": "debian:8", 29 | "Severity": "Low" 30 | } 31 | }, 32 | { 33 | "Vulnerability": { 34 | "CVSS": [], 35 | "Description": "", 36 | "FixedIn": [ 37 | { 38 | "Name": "rsyslog", 39 | "NamespaceName": "debian:8", 40 | "VendorAdvisory": { 41 | "AdvisorySummary": [], 42 | "NoAdvisory": false 43 | }, 44 | "Version": "3.18.6-1", 45 | "VersionFormat": "dpkg" 46 | } 47 | ], 48 | "Link": "https://security-tracker.debian.org/tracker/CVE-2008-5618", 49 | "Metadata": { 50 | "NVD": { 51 | "CVSSv2": { 52 | "Score": 5, 53 | "Vectors": "AV:N/AC:L/Au:N/C:N/I:N/A:P" 54 | } 55 | } 56 | }, 57 | "Name": "CVE-2008-5618", 58 | "NamespaceName": "debian:8", 59 | "Severity": "Low" 60 | } 61 | } 62 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/debian-8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "asterisk", 9 | "NamespaceName": "debian:8", 10 | "VendorAdvisory": { 11 | "AdvisorySummary": [], 12 | "NoAdvisory": false 13 | }, 14 | "Version": "1:1.6.2.0~rc3-1", 15 | "VersionFormat": "dpkg" 16 | }, 17 | { 18 | "Name": "auth2db", 19 | "NamespaceName": "debian:8", 20 | "VendorAdvisory": { 21 | "AdvisorySummary": [], 22 | "NoAdvisory": false 23 | }, 24 | "Version": "0.2.5-2+dfsg-1", 25 | "VersionFormat": "dpkg" 26 | }, 27 | { 28 | "Name": "exaile", 29 | "NamespaceName": "debian:8", 30 | "VendorAdvisory": { 31 | "AdvisorySummary": [], 32 | "NoAdvisory": false 33 | }, 34 | "Version": "0.2.14+debian-2.2", 35 | "VersionFormat": "dpkg" 36 | }, 37 | { 38 | "Name": "wordpress", 39 | "NamespaceName": "debian:8", 40 | "VendorAdvisory": { 41 | "AdvisorySummary": [], 42 | "NoAdvisory": false 43 | }, 44 | "Version": "", 45 | "VersionFormat": "dpkg" 46 | } 47 | ], 48 | "Link": "https://security-tracker.debian.org/tracker/CVE-2008-7220", 49 | "Metadata": { 50 | "NVD": { 51 | "CVSSv2": { 52 | "Score": 7.5, 53 | "Vectors": "AV:N/AC:L/Au:N/C:P/I:P/A:P" 54 | } 55 | } 56 | }, 57 | "Name": "CVE-2008-7220", 58 | "NamespaceName": "debian:8", 59 | "Severity": "High" 60 | } 61 | } 62 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/mariner-20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Name": "CVE-2021-37621", 5 | "NamespaceName": "mariner:2.0", 6 | "Description": "CVE-2021-37621 affecting package exiv2 for versions less than 0.27.5-1. An upgraded version of the package is available that resolves this issue.", 7 | "Severity": "Medium", 8 | "Link": "https://nvd.nist.gov/vuln/detail/CVE-2021-37621", 9 | "CVSS": [], 10 | "FixedIn": [ 11 | { 12 | "Name": "exiv2", 13 | "NamespaceName": "mariner:2.0", 14 | "VersionFormat": "rpm", 15 | "Version": "0:0.27.5-1.cm2", 16 | "Module": "", 17 | "VendorAdvisory": { 18 | "NoAdvisory": false, 19 | "AdvisorySummary": [] 20 | } 21 | } 22 | ], 23 | "Metadata": {} 24 | } 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/mariner-range.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Name": "CVE-2023-29404", 5 | "NamespaceName": "mariner:2.0", 6 | "Description": "CVE-2023-29404 affecting package golang for versions less than 1.20.7-1. A patched version of the package is available.", 7 | "Severity": "Critical", 8 | "Link": "https://nvd.nist.gov/vuln/detail/CVE-2023-29404", 9 | "CVSS": [], 10 | "FixedIn": [ 11 | { 12 | "Name": "golang", 13 | "NamespaceName": "mariner:2.0", 14 | "VersionFormat": "rpm", 15 | "Version": "0:1.20.7-1.cm2", 16 | "Module": "", 17 | "VendorAdvisory": { 18 | "NoAdvisory": false, 19 | "AdvisorySummary": [] 20 | }, 21 | "VulnerableRange": "> 0:1.19.0.cm2, < 0:1.20.7-1.cm2" 22 | } 23 | ], 24 | "Metadata": {} 25 | } 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/ol-8-modules.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", 6 | "FixedIn": [ 7 | { 8 | "Module": "postgresql:10", 9 | "Name": "postgresql", 10 | "NamespaceName": "ol:8", 11 | "Version": "0:10.14-1.module+el8.2.0+7801+be0fed80", 12 | "VersionFormat": "rpm" 13 | }, 14 | { 15 | "Module": "postgresql:12", 16 | "Name": "postgresql", 17 | "NamespaceName": "ol:8", 18 | "Version": "0:12.5-1.module+el8.3.0+9042+664538f4", 19 | "VersionFormat": "rpm" 20 | }, 21 | { 22 | "Module": "postgresql:9.6", 23 | "Name": "postgresql", 24 | "NamespaceName": "ol:8", 25 | "Version": "0:9.6.20-1.module+el8.3.0+8938+7f0e88b6", 26 | "VersionFormat": "rpm" 27 | } 28 | ], 29 | "Link": "https://access.redhat.com/security/cve/CVE-2020-14350", 30 | "Metadata": {}, 31 | "Name": "CVE-2020-14350", 32 | "NamespaceName": "ol:8", 33 | "Severity": "Medium" 34 | } 35 | } 36 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/os/test-fixtures/ol-8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "libexif", 9 | "NamespaceName": "ol:8", 10 | "Version": "0:0.6.21-17.el8_2", 11 | "VersionFormat": "rpm" 12 | }, 13 | { 14 | "Name": "libexif-devel", 15 | "NamespaceName": "ol:8", 16 | "Version": "0:0.6.21-17.el8_2", 17 | "VersionFormat": "rpm" 18 | }, 19 | { 20 | "Name": "libexif-dummy", 21 | "NamespaceName": "ol:8", 22 | "Version": "None", 23 | "VersionFormat": "rpm" 24 | } 25 | ], 26 | "Link": "http://linux.oracle.com/errata/ELSA-2020-2550.html", 27 | "Metadata": { 28 | "CVE": [ 29 | { 30 | "Link": "http://linux.oracle.com/cve/CVE-2020-13112.html", 31 | "Name": "CVE-2020-13112" 32 | } 33 | ], 34 | "Issued": "2020-06-15", 35 | "RefId": "ELSA-2020-2550" 36 | }, 37 | "Name": "ELSA-2020-2550", 38 | "NamespaceName": "ol:8", 39 | "Severity": "Medium" 40 | } 41 | } 42 | ] -------------------------------------------------------------------------------- /pkg/process/v5/transformers/vulnerability_metadata.go: -------------------------------------------------------------------------------- 1 | package transformers 2 | 3 | // VendorBaseMetrics captures extra metrics that do not fit into a common CVSS 4 | // struct, like Status and BaseSeverity 5 | type VendorBaseMetrics struct { 6 | BaseSeverity string `json:"base_severity"` 7 | Status string `json:"status"` 8 | } 9 | -------------------------------------------------------------------------------- /pkg/process/v6/internal/tests/utils.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | func CloseFile(f *os.File) { 9 | err := f.Close() 10 | 11 | if err != nil { 12 | log.Fatal("error closing file") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pkg/process/v6/processors.go: -------------------------------------------------------------------------------- 1 | package v6 2 | 3 | import ( 4 | "github.com/scylladb/go-set/strset" 5 | 6 | "github.com/anchore/grype-db/pkg/data" 7 | "github.com/anchore/grype-db/pkg/process/processors" 8 | "github.com/anchore/grype-db/pkg/process/v6/transformers/epss" 9 | "github.com/anchore/grype-db/pkg/process/v6/transformers/github" 10 | "github.com/anchore/grype-db/pkg/process/v6/transformers/kev" 11 | "github.com/anchore/grype-db/pkg/process/v6/transformers/msrc" 12 | "github.com/anchore/grype-db/pkg/process/v6/transformers/nvd" 13 | "github.com/anchore/grype-db/pkg/process/v6/transformers/os" 14 | "github.com/anchore/grype-db/pkg/process/v6/transformers/osv" 15 | ) 16 | 17 | type Config struct { 18 | NVD nvd.Config 19 | } 20 | 21 | type Option func(cfg *Config) 22 | 23 | func WithCPEParts(included []string) Option { 24 | return func(cfg *Config) { 25 | cfg.NVD.CPEParts = strset.New(included...) 26 | } 27 | } 28 | 29 | func WithInferNVDFixVersions(infer bool) Option { 30 | return func(cfg *Config) { 31 | cfg.NVD.InferNVDFixVersions = infer 32 | } 33 | } 34 | 35 | func NewConfig(options ...Option) Config { 36 | var cfg Config 37 | for _, option := range options { 38 | option(&cfg) 39 | } 40 | 41 | return cfg 42 | } 43 | 44 | func Processors(cfg Config) []data.Processor { 45 | return []data.Processor{ 46 | processors.NewV2GitHubProcessor(github.Transform), 47 | processors.NewV2MSRCProcessor(msrc.Transform), 48 | processors.NewV2NVDProcessor(nvd.Transformer(cfg.NVD)), 49 | processors.NewV2OSProcessor(os.Transform), 50 | processors.NewV2OSVProcessor(osv.Transform), 51 | processors.NewV2KEVProcessor(kev.Transform), 52 | processors.NewV2EPSSProcessor(epss.Transform), 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/epss/test-fixtures/go-case.json: -------------------------------------------------------------------------------- 1 | { 2 | "cve": "CVE-2025-0108", 3 | "epss": 0.328, 4 | "percentile": 0.9929, 5 | "date": "2025-02-18" 6 | } -------------------------------------------------------------------------------- /pkg/process/v6/transformers/epss/transform.go: -------------------------------------------------------------------------------- 1 | package epss 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/anchore/grype-db/pkg/data" 8 | "github.com/anchore/grype-db/pkg/process/v6/transformers" 9 | "github.com/anchore/grype-db/pkg/process/v6/transformers/internal" 10 | "github.com/anchore/grype-db/pkg/provider" 11 | "github.com/anchore/grype-db/pkg/provider/unmarshal" 12 | grypeDB "github.com/anchore/grype/grype/db/v6" 13 | ) 14 | 15 | func Transform(entry unmarshal.EPSS, state provider.State) ([]data.Entry, error) { 16 | date := internal.ParseTime(entry.Date) 17 | if date == nil { 18 | return nil, fmt.Errorf("failed to parse date: %q", entry.Date) 19 | } 20 | return transformers.NewEntries(*internal.ProviderModel(state), getEPSS(entry, *date)), nil 21 | } 22 | 23 | func getEPSS(entry unmarshal.EPSS, date time.Time) grypeDB.EpssHandle { 24 | return grypeDB.EpssHandle{ 25 | Cve: entry.CVE, 26 | Epss: entry.EPSS, 27 | Percentile: entry.Percentile, 28 | Date: date, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/GHSA-2wgc-48g2-cj5w.json: -------------------------------------------------------------------------------- 1 | { 2 | "Vulnerability": {}, 3 | "Advisory": { 4 | "Classification": "GENERAL", 5 | "Severity": "Medium", 6 | "CVSS": { 7 | "version": "3.1", 8 | "vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 9 | "base_metrics": { 10 | "base_score": 6.5, 11 | "exploitability_score": 3.9, 12 | "impact_score": 2.5, 13 | "base_severity": "Medium" 14 | }, 15 | "status": "N/A" 16 | }, 17 | "FixedIn": [ 18 | { 19 | "name": "vantage6", 20 | "identifier": "4.2.0", 21 | "ecosystem": "python", 22 | "namespace": "github:python", 23 | "range": "< 4.2.0" 24 | } 25 | ], 26 | "Summary": "vantage6 has insecure SSH configuration for node and server containers", 27 | "url": "https://github.com/advisories/GHSA-2wgc-48g2-cj5w", 28 | "CVE": [ 29 | "CVE-2024-21653" 30 | ], 31 | "Metadata": { 32 | "CVE": [ 33 | "CVE-2024-21653" 34 | ] 35 | }, 36 | "ghsaId": "GHSA-2wgc-48g2-cj5w", 37 | "published": "2024-01-30T20:56:46Z", 38 | "updated": "2024-02-08T22:48:31Z", 39 | "withdrawn": null, 40 | "namespace": "github:python" 41 | } 42 | } -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/GHSA-3x74-v64j-qc3f.json: -------------------------------------------------------------------------------- 1 | { 2 | "Vulnerability": {}, 3 | "Advisory": { 4 | "Classification": "GENERAL", 5 | "Severity": "HIGH", 6 | "CVSS": { 7 | "version": "3.1", 8 | "vector_string": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 9 | "base_metrics": { 10 | "base_score": 9.8, 11 | "exploitability_score": null, 12 | "impact_score": null, 13 | "base_severity": "HIGH" 14 | }, 15 | "status": "N/A" 16 | }, 17 | "FixedIn": [ 18 | { 19 | "name": "craftcms/cms", 20 | "identifier": "4.4.2", 21 | "ecosystem": "Packagist", 22 | "namespace": "github:Packagist", 23 | "range": "< 4.4.2" 24 | } 25 | ], 26 | "Summary": "Withdrawn Advisory: CraftCMS Server-Side Template Injection vulnerability", 27 | "url": "https://github.com/advisories/GHSA-3x74-v64j-qc3f", 28 | "CVE": [ 29 | "CVE-2023-30179" 30 | ], 31 | "Metadata": { 32 | "CVE": [ 33 | "CVE-2023-30179" 34 | ] 35 | }, 36 | "ghsaId": "GHSA-3x74-v64j-qc3f", 37 | "published": "2023-06-13T18:30:39Z", 38 | "updated": "2024-03-21T17:48:19Z", 39 | "withdrawn": "2023-06-28T23:54:39Z", 40 | "namespace": "github:Packagist" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/GHSA-92cp-5422-2mw7.json: -------------------------------------------------------------------------------- 1 | { 2 | "Vulnerability": {}, 3 | "Advisory": { 4 | "Classification": "GENERAL", 5 | "Severity": "Low", 6 | "CVSS": { 7 | "version": "3.1", 8 | "vector_string": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", 9 | "base_metrics": { 10 | "base_score": 3.7, 11 | "exploitability_score": 2.2, 12 | "impact_score": 1.4, 13 | "base_severity": "Low" 14 | }, 15 | "status": "N/A" 16 | }, 17 | "FixedIn": [ 18 | { 19 | "name": "github.com/redis/go-redis/v9", 20 | "identifier": "9.7.3", 21 | "ecosystem": "go", 22 | "namespace": "github:go", 23 | "range": ">= 9.7.0-beta.1 < 9.7.3" 24 | }, 25 | { 26 | "name": "github.com/redis/go-redis/v9", 27 | "identifier": "9.6.3", 28 | "ecosystem": "go", 29 | "namespace": "github:go", 30 | "range": ">= 9.6.0b1 < 9.6.3" 31 | }, 32 | { 33 | "name": "github.com/redis/go-redis/v9", 34 | "identifier": "9.5.5", 35 | "ecosystem": "go", 36 | "namespace": "github:go", 37 | "range": ">= 9.5.1 < 9.5.5" 38 | } 39 | ], 40 | "Summary": "go-redis allows potential out of order responses when `CLIENT SETINFO` times out during connection establishment", 41 | "url": "https://github.com/advisories/GHSA-92cp-5422-2mw7", 42 | "CVE": [ 43 | "CVE-2025-29923" 44 | ], 45 | "Metadata": { 46 | "CVE": [ 47 | "CVE-2025-29923" 48 | ] 49 | }, 50 | "ghsaId": "GHSA-92cp-5422-2mw7", 51 | "published": "2025-03-20T18:49:59Z", 52 | "updated": "2025-03-20T18:50:01Z", 53 | "withdrawn": null, 54 | "namespace": "github:go" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/github-github-npm-0.json: -------------------------------------------------------------------------------- 1 | { 2 | "Advisory": { 3 | "Classification": "GENERAL", 4 | "Severity": "Critical", 5 | "CVSS": { 6 | "version": "3.1", 7 | "vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 8 | "base_metrics": { 9 | "base_score": 9.8, 10 | "exploitability_score": 3.9, 11 | "impact_score": 5.9, 12 | "base_severity": "Critical" 13 | }, 14 | "status": "N/A" 15 | }, 16 | "FixedIn": [ 17 | { 18 | "name": "scratch-vm", 19 | "identifier": "0.2.0-prerelease.20200714185213", 20 | "ecosystem": "npm", 21 | "namespace": "github:npm", 22 | "range": "<= 0.2.0-prerelease.20200709173451" 23 | } 24 | ], 25 | "Summary": "Remote Code Execution in scratch-vm", 26 | "url": "https://github.com/advisories/GHSA-vc9j-fhvv-8vrf", 27 | "CVE": [ 28 | "CVE-2020-14000" 29 | ], 30 | "Metadata": { 31 | "CVE": [ 32 | "CVE-2020-14000" 33 | ] 34 | }, 35 | "ghsaId": "GHSA-vc9j-fhvv-8vrf", 36 | "published": "2020-07-27T19:55:52Z", 37 | "updated": "2023-01-09T05:03:39Z", 38 | "withdrawn": null, 39 | "namespace": "github:npm" 40 | } 41 | } -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/github-github-python-0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2018-8768" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "5.4.1", 11 | "name": "notebook", 12 | "namespace": "github:python", 13 | "range": "< 5.4.1" 14 | } 15 | ], 16 | "Metadata": { 17 | "CVE": [ 18 | "CVE-2018-8768" 19 | ] 20 | }, 21 | "Severity": "Low", 22 | "Summary": "Low severity vulnerability that affects notebook", 23 | "ghsaId": "GHSA-6cwv-x26c-w2q4", 24 | "namespace": "github:python", 25 | "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", 26 | "withdrawn": null 27 | }, 28 | "Vulnerability": {} 29 | }, 30 | { 31 | "Advisory": { 32 | "CVE": [ 33 | "CVE-2017-5524" 34 | ], 35 | "FixedIn": [ 36 | { 37 | "ecosystem": "python", 38 | "identifier": "4.3.12", 39 | "name": "Plone", 40 | "namespace": "github:python", 41 | "range": ">= 4.0 < 4.3.12" 42 | } 43 | ], 44 | "Metadata": { 45 | "CVE": [ 46 | "CVE-2017-5524" 47 | ] 48 | }, 49 | "Severity": "Medium", 50 | "Summary": "Moderate severity vulnerability that affects Plone", 51 | "ghsaId": "GHSA-p5wr-vp8g-q5p4", 52 | "namespace": "github:python", 53 | "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", 54 | "withdrawn": null 55 | }, 56 | "Vulnerability": {} 57 | } 58 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/github-withdrawn.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2018-8768" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "5.4.1", 11 | "name": "notebook", 12 | "namespace": "github:python", 13 | "range": "< 5.4.1" 14 | } 15 | ], 16 | "Metadata": { 17 | "CVE": [ 18 | "CVE-2018-8768" 19 | ] 20 | }, 21 | "Severity": "Low", 22 | "Summary": "Low severity vulnerability that affects notebook", 23 | "ghsaId": "GHSA-6cwv-x26c-w2q4", 24 | "namespace": "github:python", 25 | "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", 26 | "withdrawn": "2022-01-31T14:32:09Z" 27 | }, 28 | "Vulnerability": {} 29 | } 30 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/github/test-fixtures/multiple-fixed-in-names.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Advisory": { 4 | "CVE": [ 5 | "CVE-2017-5524" 6 | ], 7 | "FixedIn": [ 8 | { 9 | "ecosystem": "python", 10 | "identifier": "4.3.12", 11 | "name": "Plone", 12 | "namespace": "github:python", 13 | "range": ">= 4.0 < 4.3.12" 14 | }, 15 | { 16 | "ecosystem": "python", 17 | "identifier": "5.1b1", 18 | "name": "Plone", 19 | "namespace": "github:python", 20 | "range": ">= 5.1a1 < 5.1b1" 21 | }, 22 | { 23 | "ecosystem": "python", 24 | "identifier": "5.0.7", 25 | "name": "Plone-debug", 26 | "namespace": "github:python", 27 | "range": ">= 5.0rc1 < 5.0.7" 28 | } 29 | ], 30 | "Metadata": { 31 | "CVE": [ 32 | "CVE-2017-5524" 33 | ] 34 | }, 35 | "Severity": "Medium", 36 | "Summary": "Moderate severity vulnerability that affects Plone", 37 | "ghsaId": "GHSA-p5wr-vp8g-q5p4", 38 | "namespace": "github:python", 39 | "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", 40 | "withdrawn": null 41 | }, 42 | "Vulnerability": {} 43 | } 44 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/internal/provider.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/anchore/grype-db/pkg/provider" 7 | grypeDB "github.com/anchore/grype/grype/db/v6" 8 | ) 9 | 10 | func ProviderModel(state provider.State) *grypeDB.Provider { 11 | var digest string 12 | if state.Listing != nil { 13 | if state.Listing.Algorithm != "" && state.Listing.Digest != "" { 14 | digest = state.Listing.Algorithm + ":" + state.Listing.Digest 15 | } 16 | } 17 | return &grypeDB.Provider{ 18 | ID: state.Provider, 19 | Version: fmt.Sprintf("%d", state.Version), 20 | Processor: state.Processor, 21 | DateCaptured: &state.Timestamp, 22 | InputDigest: digest, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/internal/sort.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import grypeDB "github.com/anchore/grype/grype/db/v6" 4 | 5 | type ByAffectedPackage []grypeDB.AffectedPackageHandle 6 | 7 | func (a ByAffectedPackage) Len() int { return len(a) } 8 | func (a ByAffectedPackage) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 9 | func (a ByAffectedPackage) Less(i, j int) bool { 10 | if a[i].Package.Name == a[j].Package.Name { 11 | if a[i].Package.Ecosystem == a[j].Package.Ecosystem { 12 | for _, b := range a[i].BlobValue.Ranges { 13 | for _, c := range a[j].BlobValue.Ranges { 14 | if b.Version.Constraint != c.Version.Constraint { 15 | return b.Version.Constraint < c.Version.Constraint 16 | } 17 | } 18 | } 19 | } 20 | return a[i].Package.Ecosystem < a[j].Package.Ecosystem 21 | } 22 | return a[i].Package.Name < a[j].Package.Name 23 | } 24 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/internal/time.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "strings" 5 | "time" 6 | 7 | "github.com/araddon/dateparse" 8 | 9 | "github.com/anchore/grype-db/internal/log" 10 | ) 11 | 12 | func ParseTime(s string) *time.Time { 13 | s = strings.TrimSpace(s) 14 | if s == "" { 15 | return nil 16 | } 17 | t, err := time.Parse(time.RFC3339, s) 18 | if err == nil { 19 | return &t 20 | } 21 | 22 | // check if the timezone information is missing and append UTC if needed 23 | if !strings.Contains(s, "Z") && !strings.Contains(s, "+") && !strings.Contains(s, "-") { 24 | s += "Z" 25 | t, err = time.Parse(time.RFC3339, s) 26 | if err == nil { 27 | t = t.UTC() 28 | return &t 29 | } 30 | } 31 | 32 | // handle formats with milliseconds but no timezone 33 | formats := []string{ 34 | "2006-01-02T15:04:05.000", 35 | "2006-01-02T15:04:05.000Z", 36 | } 37 | 38 | for _, format := range formats { 39 | t, err = time.Parse(format, s) 40 | if err == nil { 41 | t = t.UTC() 42 | return &t 43 | } 44 | } 45 | 46 | // handle a wide variety of other formats 47 | t, err = dateparse.ParseAny(s) 48 | if err == nil { 49 | t = t.UTC() 50 | return &t 51 | } 52 | 53 | log.WithFields("time", s).Warnf("could not parse time: %v", err) 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/kev/test-fixtures/go-case.json: -------------------------------------------------------------------------------- 1 | { 2 | "cveID": "CVE-2025-0108", 3 | "vendorProject": "Palo Alto Networks", 4 | "product": "PAN-OS", 5 | "vulnerabilityName": "Palo Alto Networks PAN-OS Authentication Bypass Vulnerability", 6 | "dateAdded": "2025-02-18", 7 | "shortDescription": "Palo Alto Networks PAN-OS contains an authentication bypass vulnerability in its management web interface. This vulnerability allows an unauthenticated attacker with network access to the management web interface to bypass the authentication normally required and invoke certain PHP scripts.", 8 | "requiredAction": "Apply mitigations per vendor instructions [https://www.vendor.com/instructions] or discontinue use of the product if mitigations are unavailable [https:\/\/www.vendor.com\/something-else].", 9 | "dueDate": "2025-03-11", 10 | "knownRansomwareCampaignUse": "Unknown", 11 | "notes": "https:\/\/security.paloaltonetworks.com\/CVE-2025-0108 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-0108 ; remaining information", 12 | "cwes": [ 13 | "CWE-306" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/alpine-3.9.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "xen", 9 | "NamespaceName": "alpine:3.9", 10 | "Version": "4.11.1-r0", 11 | "VersionFormat": "apk" 12 | } 13 | ], 14 | "Link": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967", 15 | "Metadata": { 16 | "NVD": { 17 | "CVSSv2": { 18 | "Score": 4.9, 19 | "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:C" 20 | } 21 | } 22 | }, 23 | "Name": "CVE-2018-19967", 24 | "NamespaceName": "alpine:3.9", 25 | "Severity": "Medium" 26 | } 27 | } 28 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/amzn.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Description": "", 5 | "FixedIn": [ 6 | { 7 | "Name": "389-ds-base", 8 | "NamespaceName": "amzn:2", 9 | "Version": "1.3.8.4-15.amzn2.0.1", 10 | "VersionFormat": "rpm" 11 | }, 12 | { 13 | "Name": "389-ds-base-debuginfo", 14 | "NamespaceName": "amzn:2", 15 | "Version": "1.3.8.4-15.amzn2.0.1", 16 | "VersionFormat": "rpm" 17 | }, 18 | { 19 | "Name": "389-ds-base-devel", 20 | "NamespaceName": "amzn:2", 21 | "Version": "1.3.8.4-15.amzn2.0.1", 22 | "VersionFormat": "rpm" 23 | }, 24 | { 25 | "Name": "389-ds-base-libs", 26 | "NamespaceName": "amzn:2", 27 | "Version": "1.3.8.4-15.amzn2.0.1", 28 | "VersionFormat": "rpm" 29 | }, 30 | { 31 | "Name": "389-ds-base-snmp", 32 | "NamespaceName": "amzn:2", 33 | "Version": "1.3.8.4-15.amzn2.0.1", 34 | "VersionFormat": "rpm" 35 | } 36 | ], 37 | "Link": "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", 38 | "Metadata": { 39 | "CVE": [ 40 | { 41 | "Name": "CVE-2018-14648" 42 | } 43 | ] 44 | }, 45 | "Name": "ALAS-2018-1106", 46 | "NamespaceName": "amzn:2", 47 | "Severity": "Medium" 48 | } 49 | } 50 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/azure-linux-3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Name": "CVE-2023-29403", 5 | "NamespaceName": "mariner:3.0", 6 | "Description": "CVE-2023-29403 affecting package golang for versions less than 1.20.7-1. A patched version of the package is available.", 7 | "Severity": "High", 8 | "Link": "https://nvd.nist.gov/vuln/detail/CVE-2023-29403", 9 | "CVSS": [], 10 | "FixedIn": [ 11 | { 12 | "Name": "golang", 13 | "NamespaceName": "mariner:3.0", 14 | "VersionFormat": "rpm", 15 | "Version": "0:1.20.7-1.azl3", 16 | "Module": "", 17 | "VendorAdvisory": { 18 | "NoAdvisory": false, 19 | "AdvisorySummary": [] 20 | } 21 | } 22 | ], 23 | "Metadata": {} 24 | } 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "rsyslog", 9 | "NamespaceName": "debian:8", 10 | "VendorAdvisory": { 11 | "AdvisorySummary": [], 12 | "NoAdvisory": false 13 | }, 14 | "Version": "5.7.4-1", 15 | "VersionFormat": "dpkg" 16 | } 17 | ], 18 | "Link": "https://security-tracker.debian.org/tracker/CVE-2011-4623", 19 | "Metadata": { 20 | "NVD": { 21 | "CVSSv2": { 22 | "Score": 2.1, 23 | "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:P" 24 | } 25 | } 26 | }, 27 | "Name": "CVE-2011-4623", 28 | "NamespaceName": "debian:8", 29 | "Severity": "Low" 30 | } 31 | }, 32 | { 33 | "Vulnerability": { 34 | "CVSS": [], 35 | "Description": "", 36 | "FixedIn": [ 37 | { 38 | "Name": "rsyslog", 39 | "NamespaceName": "debian:8", 40 | "VendorAdvisory": { 41 | "AdvisorySummary": [], 42 | "NoAdvisory": false 43 | }, 44 | "Version": "3.18.6-1", 45 | "VersionFormat": "dpkg" 46 | } 47 | ], 48 | "Link": "https://security-tracker.debian.org/tracker/CVE-2008-5618", 49 | "Metadata": { 50 | "NVD": { 51 | "CVSSv2": { 52 | "Score": 5, 53 | "Vectors": "AV:N/AC:L/Au:N/C:N/I:N/A:P" 54 | } 55 | } 56 | }, 57 | "Name": "CVE-2008-5618", 58 | "NamespaceName": "debian:8", 59 | "Severity": "Low" 60 | } 61 | } 62 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/debian-8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "asterisk", 9 | "NamespaceName": "debian:8", 10 | "VendorAdvisory": { 11 | "AdvisorySummary": [], 12 | "NoAdvisory": false 13 | }, 14 | "Version": "1:1.6.2.0~rc3-1", 15 | "VersionFormat": "dpkg" 16 | }, 17 | { 18 | "Name": "auth2db", 19 | "NamespaceName": "debian:8", 20 | "VendorAdvisory": { 21 | "AdvisorySummary": [], 22 | "NoAdvisory": false 23 | }, 24 | "Version": "0.2.5-2+dfsg-1", 25 | "VersionFormat": "dpkg" 26 | }, 27 | { 28 | "Name": "exaile", 29 | "NamespaceName": "debian:8", 30 | "VendorAdvisory": { 31 | "AdvisorySummary": [], 32 | "NoAdvisory": false 33 | }, 34 | "Version": "0.2.14+debian-2.2", 35 | "VersionFormat": "dpkg" 36 | }, 37 | { 38 | "Name": "wordpress", 39 | "NamespaceName": "debian:8", 40 | "VendorAdvisory": { 41 | "AdvisorySummary": [], 42 | "NoAdvisory": false 43 | }, 44 | "Version": "", 45 | "VersionFormat": "dpkg" 46 | } 47 | ], 48 | "Link": "https://security-tracker.debian.org/tracker/CVE-2008-7220", 49 | "Metadata": { 50 | "NVD": { 51 | "CVSSv2": { 52 | "Score": 7.5, 53 | "Vectors": "AV:N/AC:L/Au:N/C:P/I:P/A:P" 54 | } 55 | } 56 | }, 57 | "Name": "CVE-2008-7220", 58 | "NamespaceName": "debian:8", 59 | "Severity": "High" 60 | } 61 | } 62 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/mariner-20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Name": "CVE-2021-37621", 5 | "NamespaceName": "mariner:2.0", 6 | "Description": "CVE-2021-37621 affecting package exiv2 for versions less than 0.27.5-1. An upgraded version of the package is available that resolves this issue.", 7 | "Severity": "Medium", 8 | "Link": "https://nvd.nist.gov/vuln/detail/CVE-2021-37621", 9 | "CVSS": [], 10 | "FixedIn": [ 11 | { 12 | "Name": "exiv2", 13 | "NamespaceName": "mariner:2.0", 14 | "VersionFormat": "rpm", 15 | "Version": "0:0.27.5-1.cm2", 16 | "Module": "", 17 | "VendorAdvisory": { 18 | "NoAdvisory": false, 19 | "AdvisorySummary": [] 20 | } 21 | } 22 | ], 23 | "Metadata": {} 24 | } 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/mariner-range.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "Name": "CVE-2023-29404", 5 | "NamespaceName": "mariner:2.0", 6 | "Description": "CVE-2023-29404 affecting package golang for versions less than 1.20.7-1. A patched version of the package is available.", 7 | "Severity": "Critical", 8 | "Link": "https://nvd.nist.gov/vuln/detail/CVE-2023-29404", 9 | "CVSS": [], 10 | "FixedIn": [ 11 | { 12 | "Name": "golang", 13 | "NamespaceName": "mariner:2.0", 14 | "VersionFormat": "rpm", 15 | "Version": "0:1.20.7-1.cm2", 16 | "Module": "", 17 | "VendorAdvisory": { 18 | "NoAdvisory": false, 19 | "AdvisorySummary": [] 20 | }, 21 | "VulnerableRange": "> 0:1.19.0.cm2, < 0:1.20.7-1.cm2" 22 | } 23 | ], 24 | "Metadata": {} 25 | } 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/ol-8-modules.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", 6 | "FixedIn": [ 7 | { 8 | "Module": "postgresql:10", 9 | "Name": "postgresql", 10 | "NamespaceName": "ol:8", 11 | "Version": "0:10.14-1.module+el8.2.0+7801+be0fed80", 12 | "VersionFormat": "rpm" 13 | }, 14 | { 15 | "Module": "postgresql:12", 16 | "Name": "postgresql", 17 | "NamespaceName": "ol:8", 18 | "Version": "0:12.5-1.module+el8.3.0+9042+664538f4", 19 | "VersionFormat": "rpm" 20 | }, 21 | { 22 | "Module": "postgresql:9.6", 23 | "Name": "postgresql", 24 | "NamespaceName": "ol:8", 25 | "Version": "0:9.6.20-1.module+el8.3.0+8938+7f0e88b6", 26 | "VersionFormat": "rpm" 27 | } 28 | ], 29 | "Link": "https://access.redhat.com/security/cve/CVE-2020-14350", 30 | "Metadata": {}, 31 | "Name": "CVE-2020-14350", 32 | "NamespaceName": "ol:8", 33 | "Severity": "Medium" 34 | } 35 | } 36 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/os/test-fixtures/ol-8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Vulnerability": { 4 | "CVSS": [], 5 | "Description": "", 6 | "FixedIn": [ 7 | { 8 | "Name": "libexif", 9 | "NamespaceName": "ol:8", 10 | "Version": "0:0.6.21-17.el8_2", 11 | "VersionFormat": "rpm" 12 | }, 13 | { 14 | "Name": "libexif-devel", 15 | "NamespaceName": "ol:8", 16 | "Version": "0:0.6.21-17.el8_2", 17 | "VersionFormat": "rpm" 18 | }, 19 | { 20 | "Name": "libexif-dummy", 21 | "NamespaceName": "ol:8", 22 | "Version": "None", 23 | "VersionFormat": "rpm" 24 | } 25 | ], 26 | "Link": "http://linux.oracle.com/errata/ELSA-2020-2550.html", 27 | "Metadata": { 28 | "CVE": [ 29 | { 30 | "Link": "http://linux.oracle.com/cve/CVE-2020-13112.html", 31 | "Name": "CVE-2020-13112" 32 | } 33 | ], 34 | "Issued": "2020-06-15", 35 | "RefId": "ELSA-2020-2550" 36 | }, 37 | "Name": "ELSA-2020-2550", 38 | "NamespaceName": "ol:8", 39 | "Severity": "Medium" 40 | } 41 | } 42 | ] -------------------------------------------------------------------------------- /pkg/process/v6/transformers/osv/test-fixtures/BIT-apache-2020-11984.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_version": "1.5.0", 3 | "id": "BIT-apache-2020-11984", 4 | "details": "Apache HTTP server 2.4.32 to 2.4.44 mod_proxy_uwsgi info disclosure and possible RCE", 5 | "aliases": [ 6 | "CVE-2020-11984" 7 | ], 8 | "affected": [ 9 | { 10 | "package": { 11 | "ecosystem": "Bitnami", 12 | "name": "apache", 13 | "purl": "pkg:bitnami/apache" 14 | }, 15 | "severity": [ 16 | { 17 | "type": "CVSS_V3", 18 | "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" 19 | } 20 | ], 21 | "ranges": [ 22 | { 23 | "type": "SEMVER", 24 | "events": [ 25 | { 26 | "introduced": "2.4.32" 27 | }, 28 | { 29 | "last_affected": "2.4.43" 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ], 36 | "database_specific": { 37 | "severity": "Critical", 38 | "cpes": [ 39 | "cpe:2.3:a:apache:http_server:*:*:*:*:*:*:*:*" 40 | ] 41 | }, 42 | "references": [ 43 | { 44 | "type": "WEB", 45 | "url": "http://www.openwall.com/lists/oss-security/2020/08/08/1" 46 | }, 47 | { 48 | "type": "WEB", 49 | "url": "http://www.openwall.com/lists/oss-security/2020/08/08/10" 50 | } 51 | ], 52 | "published": "2024-03-06T10:57:57.770Z", 53 | "modified": "2025-01-17T15:26:01.971Z" 54 | } 55 | -------------------------------------------------------------------------------- /pkg/provider/config.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import "github.com/anchore/grype-db/internal/log" 4 | 5 | type Collection struct { 6 | Root string 7 | Providers []Provider 8 | } 9 | 10 | type Config struct { 11 | Identifier `yaml:",inline" mapstructure:",squash"` 12 | Config interface{} `yaml:"config,omitempty" json:"config" mapstructure:"config"` 13 | } 14 | 15 | func (c Config) Redact() { 16 | if c.Config == nil { 17 | return 18 | } 19 | if r, ok := c.Config.(log.Redactable); ok { 20 | r.Redact() 21 | } 22 | } 23 | 24 | type Identifier struct { 25 | Name string `yaml:"name" json:"name" mapstructure:"name"` 26 | Kind Kind `yaml:"kind,omitempty" json:"kind" mapstructure:"kind"` 27 | } 28 | -------------------------------------------------------------------------------- /pkg/provider/entry/file.go: -------------------------------------------------------------------------------- 1 | package entry 2 | 3 | import ( 4 | "io" 5 | "os" 6 | ) 7 | 8 | type fileOpener struct { 9 | path string 10 | } 11 | 12 | func fileOpeners(resultPaths []string) <-chan Opener { 13 | openers := make(chan Opener) 14 | go func() { 15 | defer close(openers) 16 | for _, p := range resultPaths { 17 | openers <- fileOpener{path: p} 18 | } 19 | }() 20 | return openers 21 | } 22 | 23 | func (e fileOpener) Open() (io.ReadCloser, error) { 24 | return os.Open(e.path) 25 | } 26 | 27 | func (e fileOpener) String() string { 28 | return e.path 29 | } 30 | -------------------------------------------------------------------------------- /pkg/provider/entry/opener.go: -------------------------------------------------------------------------------- 1 | package entry 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | type Opener interface { 9 | Open() (io.ReadCloser, error) 10 | fmt.Stringer 11 | } 12 | 13 | func Openers(store string, resultPaths []string) (<-chan Opener, int64, error) { 14 | switch store { 15 | case "flat-file": 16 | return fileOpeners(resultPaths), int64(len(resultPaths)), nil 17 | case "sqlite": 18 | return sqliteOpeners(resultPaths) 19 | } 20 | return nil, 0, fmt.Errorf("unknown store: %q", store) 21 | } 22 | 23 | func Count(store string, resultPaths []string) (int64, error) { 24 | switch store { 25 | case "flat-file": 26 | return int64(len(resultPaths)), nil 27 | case "sqlite": 28 | return sqliteEntryCount(resultPaths) 29 | } 30 | return 0, fmt.Errorf("unknown store: %q", store) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/provider/file.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | "github.com/OneOfOne/xxhash" 8 | "github.com/spf13/afero" 9 | 10 | "github.com/anchore/grype-db/internal/file" 11 | ) 12 | 13 | type File struct { 14 | Path string `json:"path"` 15 | Digest string `json:"digest"` 16 | Algorithm string `json:"algorithm"` 17 | } 18 | 19 | type Files []File 20 | 21 | func NewFile(path string) (*File, error) { 22 | digest, err := file.ContentDigest(afero.NewOsFs(), path, xxhash.New64()) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | return &File{ 28 | Path: path, 29 | Digest: digest, 30 | Algorithm: "xxh64", 31 | }, nil 32 | } 33 | 34 | func NewFiles(paths ...string) (Files, error) { 35 | var files []File 36 | for _, path := range paths { 37 | input, err := NewFile(path) 38 | if err != nil { 39 | return nil, err 40 | } 41 | files = append(files, *input) 42 | } 43 | return files, nil 44 | } 45 | 46 | func (i Files) Paths() []string { 47 | var paths []string 48 | for _, input := range i { 49 | paths = append(paths, input.Path) 50 | } 51 | return paths 52 | } 53 | 54 | func NewFilesFromDir(dir string) (Files, error) { 55 | listing, err := os.ReadDir(dir) 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | var paths []string 61 | for _, f := range listing { 62 | if f.IsDir() { 63 | continue 64 | } 65 | paths = append(paths, filepath.Join(dir, f.Name())) 66 | } 67 | 68 | return NewFiles(paths...) 69 | } 70 | -------------------------------------------------------------------------------- /pkg/provider/provider.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import "context" 4 | 5 | type Kind string 6 | 7 | const ( 8 | InternalKind Kind = "internal" // reserved, not implemented (golang vulnerability data providers in-repo) 9 | ExternalKind Kind = "external" 10 | VunnelKind Kind = "vunnel" // special case of external 11 | ) 12 | 13 | type Provider interface { 14 | ID() Identifier 15 | Update(context.Context) error 16 | State() (*State, error) 17 | } 18 | 19 | type Providers []Provider 20 | 21 | func (ps Providers) Filter(names ...string) Providers { 22 | var filtered Providers 23 | for _, p := range ps { 24 | for _, name := range names { 25 | if p.ID().Name == name { 26 | filtered = append(filtered, p) 27 | } 28 | } 29 | } 30 | return filtered 31 | } 32 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/epss.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import "io" 4 | 5 | type EPSS struct { 6 | CVE string `json:"cve"` 7 | EPSS float64 `json:"epss"` 8 | Percentile float64 `json:"percentile"` 9 | Date string `json:"date"` 10 | } 11 | 12 | func (o EPSS) IsEmpty() bool { 13 | return o.CVE == "" 14 | } 15 | 16 | func EPSSEntries(reader io.Reader) ([]EPSS, error) { 17 | return unmarshalSingleOrMulti[EPSS](reader) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/errors.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func handleJSONUnmarshalError(err error) error { 9 | if ute, ok := err.(*json.UnmarshalTypeError); ok { //nolint: errorlint 10 | return fmt.Errorf("unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset) 11 | } else if se, ok := err.(*json.SyntaxError); ok { //nolint: errorlint 12 | return fmt.Errorf("syntax error: offset=%v, error=%w", se.Offset, se) 13 | } 14 | return err 15 | } 16 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/github_advisory.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type GitHubAdvisory struct { 8 | Advisory struct { 9 | Classification string 10 | CVE []string `json:"CVE"` 11 | CVSS *struct { 12 | BaseMetrics struct { 13 | BaseScore float64 `json:"base_score"` 14 | BaseSeverity string `json:"base_severity"` 15 | ExploitabilityScore float64 `json:"exploitability_score"` 16 | ImpactScore float64 `json:"impact_score"` 17 | } `json:"base_metrics"` 18 | Status string `json:"status"` 19 | VectorString string `json:"vector_string"` 20 | Version string `json:"version"` 21 | } `json:"CVSS"` 22 | FixedIn []GithubFixedIn `json:"FixedIn"` 23 | Metadata struct { 24 | CVE []string `json:"CVE"` 25 | } `json:"Metadata"` 26 | Severity string `json:"Severity"` 27 | Summary string `json:"Summary"` 28 | GhsaID string `json:"ghsaId"` 29 | Namespace string `json:"namespace"` 30 | URL string `json:"url"` 31 | Published string `json:"published"` 32 | Updated string `json:"updated"` 33 | Withdrawn string `json:"withdrawn"` 34 | } `json:"Advisory"` 35 | } 36 | 37 | func (g GitHubAdvisory) IsEmpty() bool { 38 | return g.Advisory.GhsaID == "" 39 | } 40 | 41 | func GitHubAdvisoryEntries(reader io.Reader) ([]GitHubAdvisory, error) { 42 | return unmarshalSingleOrMulti[GitHubAdvisory](reader) 43 | } 44 | 45 | type GithubFixedIn struct { 46 | Ecosystem string `json:"ecosystem"` 47 | Identifier string `json:"identifier"` 48 | Name string `json:"name"` 49 | Namespace string `json:"namespace"` 50 | Range string `json:"range"` 51 | } 52 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/items_envelope.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | type ItemsEnvelope struct { 10 | Schema string `yaml:"schema" json:"schema" mapstructure:"schema"` 11 | Identifier string `yaml:"identifier" json:"identifier" mapstructure:"identifier"` 12 | Item json.RawMessage `yaml:"item" json:"item" mapstructure:"item"` 13 | } 14 | 15 | func Envelope(reader io.Reader) (*ItemsEnvelope, error) { 16 | var envelope ItemsEnvelope 17 | dec := json.NewDecoder(reader) 18 | err := dec.Decode(&envelope) 19 | if err != nil { 20 | return nil, fmt.Errorf("unable to open envelope: %w", err) 21 | } 22 | return &envelope, nil 23 | } 24 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/known_exploited_vulnerability.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import "io" 4 | 5 | type KnownExploitedVulnerability struct { 6 | CveID string `json:"cveID"` 7 | VendorProject string `json:"vendorProject"` 8 | Product string `json:"product"` 9 | VulnerabilityName string `json:"vulnerabilityName"` 10 | DateAdded string `json:"dateAdded"` 11 | ShortDescription string `json:"shortDescription"` 12 | RequiredAction string `json:"requiredAction"` 13 | DueDate string `json:"dueDate"` 14 | KnownRansomwareCampaignUse string `json:"knownRansomwareCampaignUse"` 15 | Notes string `json:"notes"` 16 | CWEs []string `json:"cwes"` 17 | } 18 | 19 | func (g KnownExploitedVulnerability) IsEmpty() bool { 20 | return g.CveID == "" 21 | } 22 | 23 | func KnownExploitedVulnerabilityEntries(reader io.Reader) ([]KnownExploitedVulnerability, error) { 24 | return unmarshalSingleOrMulti[KnownExploitedVulnerability](reader) 25 | } 26 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/match_exclusion.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type MatchExclusion struct { 8 | ID string `json:"id"` 9 | Constraints []struct { 10 | Vulnerability struct { 11 | Namespace string `json:"namespace,omitempty"` 12 | FixState string `json:"fix_state,omitempty"` 13 | } `json:"vulnerability,omitempty"` 14 | Package struct { 15 | Language string `json:"language,omitempty"` 16 | Type string `json:"type,omitempty"` 17 | Name string `json:"name,omitempty"` 18 | Version string `json:"version,omitempty"` 19 | Location string `json:"location,omitempty"` 20 | } `json:"package,omitempty"` 21 | } `json:"constraints,omitempty"` 22 | Justification string `json:"justification"` 23 | } 24 | 25 | func (m MatchExclusion) IsEmpty() bool { 26 | return m.ID == "" 27 | } 28 | 29 | func MatchExclusions(reader io.Reader) ([]MatchExclusion, error) { 30 | return unmarshalSingleOrMulti[MatchExclusion](reader) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/msrc_vulnerability.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // MSRCVulnerability represents a single Msrc entry with vulnerability metadata 8 | type MSRCVulnerability struct { 9 | Cvss struct { 10 | BaseScore float64 `json:"base_score"` 11 | TemporalScore float64 `json:"temporal_score"` 12 | Vector string `json:"vector"` 13 | } `json:"cvss"` 14 | FixedIn []struct { 15 | ID string `json:"id"` 16 | IsFirst bool `json:"is_first"` 17 | IsLatest bool `json:"is_latest"` 18 | Links []string `json:"links"` 19 | } `json:"fixed_in"` 20 | ID string `json:"id"` 21 | Link string `json:"link"` 22 | Product struct { 23 | Family string `json:"family"` 24 | ID string `json:"id"` 25 | Name string `json:"name"` 26 | } `json:"product"` 27 | Severity string `json:"severity"` 28 | Summary string `json:"summary"` 29 | Vulnerable []string `json:"vulnerable"` 30 | } 31 | 32 | func (o MSRCVulnerability) IsEmpty() bool { 33 | return o.ID == "" 34 | } 35 | 36 | func MSRCVulnerabilityEntries(reader io.Reader) ([]MSRCVulnerability, error) { 37 | return unmarshalSingleOrMulti[MSRCVulnerability](reader) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/nvd_vulnerability.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" 7 | ) 8 | 9 | type ( 10 | NVDVulnerability = nvd.CveItem 11 | ) 12 | 13 | func NvdVulnerabilityEntries(reader io.Reader) ([]nvd.Vulnerability, error) { 14 | return unmarshalSingleOrMulti[nvd.Vulnerability](reader) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/osv_vulnerability.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/google/osv-scanner/pkg/models" 7 | ) 8 | 9 | type OSVVulnerability = models.Vulnerability 10 | 11 | func OSVVulnerabilityEntries(reader io.Reader) ([]OSVVulnerability, error) { 12 | return unmarshalSingleOrMulti[OSVVulnerability](reader) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/provider/unmarshal/single_or_multi.go: -------------------------------------------------------------------------------- 1 | package unmarshal 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | ) 9 | 10 | func unmarshalSingleOrMulti[T interface{}](reader io.Reader) ([]T, error) { 11 | var entry T 12 | 13 | var buf bytes.Buffer 14 | r := io.TeeReader(reader, &buf) 15 | 16 | dec := json.NewDecoder(r) 17 | err := dec.Decode(&entry) 18 | if err == nil { 19 | return []T{entry}, nil 20 | } 21 | 22 | // TODO: enhance the error handling to return the original error if the item is found to not be an array of items 23 | 24 | var entries []T 25 | dec = json.NewDecoder(io.MultiReader(&buf, reader)) 26 | 27 | if err = dec.Decode(&entries); err != nil { 28 | return nil, fmt.Errorf("unable to decode vulnerability: %w", handleJSONUnmarshalError(err)) 29 | } 30 | return entries, nil 31 | } 32 | -------------------------------------------------------------------------------- /pkg/provider/workspace.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "path/filepath" 5 | ) 6 | 7 | type Workspace struct { 8 | Root string 9 | Name string 10 | } 11 | 12 | func NewWorkspace(root, name string) Workspace { 13 | return Workspace{ 14 | Root: root, 15 | Name: name, 16 | } 17 | } 18 | 19 | func NewWorkspaceFromExisting(workspacePath string) Workspace { 20 | return Workspace{ 21 | Root: filepath.Dir(workspacePath), 22 | Name: filepath.Base(workspacePath), 23 | } 24 | } 25 | 26 | func (w Workspace) Path() string { 27 | return filepath.Join(w.Root, w.Name) 28 | } 29 | 30 | func (w Workspace) StatePath() string { 31 | return filepath.Join(w.Path(), "metadata.json") 32 | } 33 | 34 | func (w Workspace) InputPath() string { 35 | return filepath.Join(w.Path(), "input") 36 | } 37 | 38 | func (w Workspace) ResultsPath() string { 39 | return filepath.Join(w.Path(), "results") 40 | } 41 | 42 | func (w Workspace) ReadState() (*State, error) { 43 | return ReadState(w.StatePath()) 44 | } 45 | -------------------------------------------------------------------------------- /test/cli/log_redaction_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestLogRedaction_CommandConfigs(t *testing.T) { 9 | secretValue := "topsy-kretts" 10 | tests := []struct { 11 | name string 12 | args []string 13 | }{ 14 | {name: "pull"}, 15 | {name: "build"}, 16 | {name: "cache status"}, 17 | } 18 | 19 | for _, test := range tests { 20 | t.Run(test.name, func(t *testing.T) { 21 | args := append(strings.Split(test.name, " "), "--dry-run", "-vv", "-c", "test-fixtures/grype-db-config-with-secrets.yaml") 22 | args = append(args, test.args...) 23 | cmd, stdout, stderr := runGrypeDB(t, nil, args...) 24 | assertions := []traitAssertion{ 25 | assertLoggingLevel("debug"), 26 | assertNotInOutput(secretValue), 27 | } 28 | for _, traitFn := range assertions { 29 | traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) 30 | } 31 | if t.Failed() { 32 | t.Log("STDOUT:\n", stdout) 33 | t.Log("STDERR:\n", stderr) 34 | t.Log("COMMAND:", strings.Join(cmd.Args, " ")) 35 | } 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/cli/test-fixtures/grype-db-config-with-secrets.yaml: -------------------------------------------------------------------------------- 1 | provider: 2 | root: ./data 3 | 4 | vunnel: 5 | executor: local 6 | env: 7 | GITHUB_TOKEN: topsy-kretts 8 | NVD_API_KEY: topsy-kretts 9 | 10 | configs: 11 | 12 | - name: oracle 13 | type: external 14 | config: 15 | env: 16 | SECRET: topsy-kretts 17 | 18 | - name: oracle 19 | type: vunnel 20 | config: 21 | env: 22 | SECRET: topsy-kretts 23 | -------------------------------------------------------------------------------- /test/db/acceptance.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | BOLD=$(tput -T linux bold) 5 | RESET=$(tput -T linux sgr0) 6 | 7 | function title() { 8 | echo "${BOLD}$1${RESET}" 9 | } 10 | 11 | SCHEMA_VERSION=${1:-} 12 | 13 | if [ -z "$SCHEMA_VERSION" ]; then 14 | echo "Usage: $0 " 15 | exit 1 16 | else 17 | title "Building DB" 18 | fi 19 | 20 | DB_ID=$(grype-db-manager -v db build --schema-version $SCHEMA_VERSION) 21 | 22 | if [ -z "$DB_ID" ]; then 23 | echo "Failed to create DB instance" 24 | exit 1 25 | fi 26 | 27 | title "Validating DB" 28 | 29 | grype-db-manager -vv db validate $DB_ID 30 | --------------------------------------------------------------------------------