-
Notifications
You must be signed in to change notification settings - Fork 1
feat: implement vdb subcommand for Vulnerability Database API #136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Implement comprehensive VDB (Vulnerability Database) API integration with the following components: Core Implementation: - internal/vdb/client.go: VDB API client with AWS SigV4 authentication * JWT token management with automatic caching and refresh * Support for environment variables and config file credentials * SHA-512 HMAC request signing for auth endpoint * HTTP client with proper timeout and error handling - internal/vdb/api.go: API endpoint methods * GetCVE: Retrieve CVE information * GetEcosystems: List available package ecosystems * GetProductVersions: Get product versions with pagination * GetProductVersion: Get specific version details * GetPackageVulnerabilities: Get package vulnerabilities * GetOpenAPISpec: Retrieve API specification CLI Commands (cmd/vdb.go): - vulnetix vdb cve <CVE-ID>: Get CVE details - vulnetix vdb ecosystems: List ecosystems - vulnetix vdb product <name> [version]: Get product info - vulnetix vdb vulns <package>: Get vulnerabilities - vulnetix vdb spec: Get OpenAPI specification Features: - AWS SigV4 (SHA-512) authentication - JWT token caching (15-minute expiry) - Pagination support (--limit, --offset) - Multiple output formats (json, pretty) - Flexible credential loading (env vars, config file, flags) - Rate limit awareness (60/min, 1000/week) - Comprehensive error handling Documentation: - docs/VDB-COMMAND.md: Complete command reference - docs/VDB-QUICKSTART.md: Quick start guide - VDB-IMPLEMENTATION.md: Implementation overview Examples: - examples/vdb-config.json: Configuration template - examples/vdb-ci-example.sh: CI/CD integration script - examples/vdb-github-action.yml: GitHub Actions workflow Based on VDB API User Guide v1 specifications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements a comprehensive VDB (Vulnerability Database) API integration for the Vulnetix CLI, enabling users to query CVE information, list package ecosystems, retrieve product versions, and find vulnerabilities through AWS SigV4 authenticated API calls.
Key Changes:
- JWT token-based authentication with AWS SigV4 SHA-512 signing and automatic token refresh
- Five new CLI subcommands (cve, ecosystems, product, vulns, spec) with pagination support and multiple output formats
- Complete documentation suite including quick start guide, command reference, and implementation overview with CI/CD integration examples
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/vdb/client.go | Core VDB API client with AWS SigV4 authentication, JWT token caching, and credential loading from environment/config |
| internal/vdb/api.go | API endpoint methods for CVE lookup, ecosystems, product versions, vulnerabilities, and OpenAPI spec retrieval |
| cmd/vdb.go | CLI command implementation with subcommands for all VDB operations, pagination support, and JSON/pretty output |
| docs/VDB-COMMAND.md | Comprehensive command reference with usage examples, authentication setup, and troubleshooting guide |
| docs/VDB-QUICKSTART.md | Quick start guide with credential setup, common use cases, and advanced tips for CLI usage |
| VDB-IMPLEMENTATION.md | Technical implementation overview covering architecture, authentication flow, and development guidelines |
| examples/vdb-config.json | Example configuration file template for storing VDB credentials |
| examples/vdb-ci-example.sh | Bash script demonstrating CI/CD integration with vulnerability scanning and severity thresholds |
| examples/vdb-github-action.yml | GitHub Actions workflow for automated vulnerability scanning with matrix strategy and reporting |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| client.BaseURL = vdbBaseURL | ||
| } | ||
|
|
||
| fmt.Println("📋 Fetching OpenAPI specification...") |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same issue exists here - informational messages are printed to stdout before JSON output. These should use stderr when vdbOutput is "json".
| VULNS_JSON=$(vulnetix vdb vulns "$PACKAGE_NAME" -o json 2>&1) | ||
|
|
||
| if [ $? -ne 0 ]; then | ||
| echo -e "${RED}❌ Failed to fetch vulnerabilities${NC}" |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses command substitution without proper error handling. If the vulnetix command fails (line 49), the script continues execution and tries to parse empty or error output with jq, which could lead to confusing error messages. The error check on line 51 comes after the variable assignment, so $? might not reflect the vulnetix command's exit status. Consider using set -o pipefail or checking the exit status before assignment.
| VULNS_JSON=$(vulnetix vdb vulns "$PACKAGE_NAME" -o json 2>&1) | |
| if [ $? -ne 0 ]; then | |
| echo -e "${RED}❌ Failed to fetch vulnerabilities${NC}" | |
| if ! VULNS_JSON=$(vulnetix vdb vulns "$PACKAGE_NAME" -o json 2>&1); then | |
| echo -es "${RED}❌ Failed to fetch vulnerabilities${NC}" |
| canonicalRequest := fmt.Sprintf("%s\n%s\n\n%s\n%s\n%s", | ||
| req.Method, | ||
| path, | ||
| canonicalHeaders, | ||
| signedHeaders, | ||
| payloadHash, | ||
| ) |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The canonical request format is missing the query string component. According to AWS SigV4 specification, the canonical request should include the canonical query string (even if empty) between the path and canonical headers. The current format has path followed directly by an empty line and headers. This should be: Method\nCanonicalURI\nCanonicalQueryString\nCanonicalHeaders\nSignedHeaders\nHashedPayload
| vdbLimit int | ||
| vdbOffset int | ||
| vdbOutput string |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The vdbLimit and vdbOffset variables are shared across both productCmd and vulnsCmd flags. This means if a user runs multiple commands in the same CLI instance or if flags are parsed in an unexpected order, these shared variables could cause flag values from one command to affect another. Consider using separate variables for each command or scoping these variables locally within each command's init function.
| @@ -0,0 +1,4 @@ | |||
| { | |||
| "org_id": "00000000-0000-0000-0000-000000000000", | |||
| "secret_key": "0000000000000000000000000000000000000000000000000000000000000000" | |||
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The secret key in this example configuration file is shown as 64 zeros, which might lead users to believe this is a valid format for testing. Consider using a more obvious placeholder like "your-secret-key-here" or "REPLACE_WITH_YOUR_SECRET_KEY" to prevent users from accidentally using dummy credentials.
| "secret_key": "0000000000000000000000000000000000000000000000000000000000000000" | |
| "secret_key": "REPLACE_WITH_YOUR_SECRET_KEY" |
| - name: Install Vulnetix CLI | ||
| run: | | ||
| # Install from GitHub releases (adjust version as needed) | ||
| curl -LO https://github.com/vulnetix/cli/releases/latest/download/vulnetix-linux-amd64 |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The curl command downloads the binary without verifying its integrity (no checksum validation). This poses a security risk as the binary could be tampered with during download or if the releases server is compromised. Consider adding checksum verification using sha256sum or providing a secure verification mechanism.
| curl -LO https://github.com/vulnetix/cli/releases/latest/download/vulnetix-linux-amd64 | |
| curl -LO https://github.com/vulnetix/cli/releases/latest/download/vulnetix-linux-amd64 | |
| curl -LO https://github.com/vulnetix/cli/releases/latest/download/vulnetix-linux-amd64.sha256 | |
| # Verify the downloaded binary against its SHA-256 checksum | |
| sha256sum -c vulnetix-linux-amd64.sha256 |
|
|
||
| // Store full response in Data field | ||
| var fullData map[string]interface{} | ||
| json.Unmarshal(respBody, &fullData) |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error returned when parsing the json.Unmarshal error is ignored. If unmarshaling fails, the error is silently discarded, and fullData will be nil or empty. This should be checked and handled, or at minimum logged, to help with debugging when the API response format changes.
| // GetPackageVulnerabilities retrieves vulnerabilities for a package | ||
| func (c *Client) GetPackageVulnerabilities(packageName string, limit, offset int) (*VulnerabilitiesResponse, error) { | ||
| path := fmt.Sprintf("/%s/vulns", url.PathEscape(packageName)) | ||
|
|
||
| // Add pagination parameters | ||
| if limit > 0 || offset > 0 { | ||
| params := url.Values{} | ||
| if limit > 0 { | ||
| params.Add("limit", fmt.Sprintf("%d", limit)) | ||
| } | ||
| if offset > 0 { | ||
| params.Add("offset", fmt.Sprintf("%d", offset)) | ||
| } | ||
| path = path + "?" + params.Encode() | ||
| } |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same pagination logic is duplicated in GetProductVersions and GetPackageVulnerabilities. Consider extracting this into a helper function like buildPaginationQuery(limit, offset int) string to improve maintainability and reduce code duplication.
| // GetPackageVulnerabilities retrieves vulnerabilities for a package | |
| func (c *Client) GetPackageVulnerabilities(packageName string, limit, offset int) (*VulnerabilitiesResponse, error) { | |
| path := fmt.Sprintf("/%s/vulns", url.PathEscape(packageName)) | |
| // Add pagination parameters | |
| if limit > 0 || offset > 0 { | |
| params := url.Values{} | |
| if limit > 0 { | |
| params.Add("limit", fmt.Sprintf("%d", limit)) | |
| } | |
| if offset > 0 { | |
| params.Add("offset", fmt.Sprintf("%d", offset)) | |
| } | |
| path = path + "?" + params.Encode() | |
| } | |
| // buildPaginationQuery constructs a query string for pagination parameters. | |
| // It returns an empty string if neither limit nor offset is greater than zero. | |
| func buildPaginationQuery(limit, offset int) string { | |
| if limit <= 0 && offset <= 0 { | |
| return "" | |
| } | |
| params := url.Values{} | |
| if limit > 0 { | |
| params.Add("limit", fmt.Sprintf("%d", limit)) | |
| } | |
| if offset > 0 { | |
| params.Add("offset", fmt.Sprintf("%d", offset)) | |
| } | |
| return "?" + params.Encode() | |
| } | |
| // GetPackageVulnerabilities retrieves vulnerabilities for a package | |
| func (c *Client) GetPackageVulnerabilities(packageName string, limit, offset int) (*VulnerabilitiesResponse, error) { | |
| path := fmt.Sprintf("/%s/vulns", url.PathEscape(packageName)) | |
| // Add pagination parameters | |
| path += buildPaginationQuery(limit, offset) |
| # Verify environment variables are set | ||
| echo $VVD_ORG | ||
| echo $VVD_SECRET | ||
|
|
||
| # Or check config file exists | ||
| cat ~/.vulnetix/vdb.json |
Copilot
AI
Dec 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The troubleshooting snippet that uses echo $VVD_SECRET and cat ~/.vulnetix/vdb.json encourages printing raw API credentials to stdout, which can leak secrets into terminal history or CI/CD logs. In shared or automated environments, anyone with log access could recover these values and impersonate the organization against the VDB API. Please adjust this guidance so users verify that credentials are configured without printing their full values or configuration contents, and explicitly discourage logging secrets in troubleshooting steps.
| # Verify environment variables are set | |
| echo $VVD_ORG | |
| echo $VVD_SECRET | |
| # Or check config file exists | |
| cat ~/.vulnetix/vdb.json | |
| # Verify environment variables are set WITHOUT printing secret values | |
| if [ -n "${VVD_ORG:-}" ]; then | |
| echo "VVD_ORG is set" | |
| else | |
| echo "VVD_ORG is NOT set" | |
| fi | |
| if [ -n "${VVD_SECRET:-}" ]; then | |
| echo "VVD_SECRET is set" | |
| else | |
| echo "VVD_SECRET is NOT set" | |
| fi | |
| # Check that the config file exists (but don't print its contents) | |
| if [ -f "$HOME/.vulnetix/vdb.json" ]; then | |
| echo "VDB config file found at $HOME/.vulnetix/vdb.json" | |
| else | |
| echo "VDB config file not found at $HOME/.vulnetix/vdb.json" | |
| fi | |
| # Security tip: avoid running commands that print secrets (UUIDs, API keys, | |
| # or full config files) directly to your terminal or CI logs. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Stof <93355168+0x73746F66@users.noreply.github.com>
Implement comprehensive VDB (Vulnerability Database) API integration
with the following components:
Core Implementation:
internal/vdb/client.go: VDB API client with AWS SigV4 authentication
internal/vdb/api.go: API endpoint methods
CLI Commands (cmd/vdb.go):
Features:
Documentation:
Examples:
Based on VDB API User Guide v1 specifications.