Skip to content

Commit 2debaf6

Browse files
committed
feat: add cloud-locators command and expand PURL ecosystem map
Add V2 cloud-locators command to retrieve AWS ARN, Azure Resource ID, GCP Resource Name, Cloudflare, and Oracle OCID templates for vendor/product pairs. Add V2CloudLocators() API client method. Expand PURL ecosystem map with conda, conan, huggingface, julia, luarocks, opam, cpan, and others.
1 parent 6279943 commit 2debaf6

3 files changed

Lines changed: 104 additions & 12 deletions

File tree

cmd/vdb_v2.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,53 @@ Examples:
355355
},
356356
}
357357

358+
// v2CloudLocatorsCmd retrieves cloud resource locator templates
359+
var v2CloudLocatorsCmd = &cobra.Command{
360+
Use: "cloud-locators",
361+
Short: "Get cloud resource locator templates for a vendor/product (V2)",
362+
Long: `Derive cloud-native resource identifier templates (AWS ARN, Azure Resource ID,
363+
GCP Resource Name, Cloudflare Locator, Oracle OCID) from vendor/product pairs.
364+
365+
Templates contain placeholders for account-specific values that you fill in
366+
to match your infrastructure resources.
367+
368+
Requires -V v2.
369+
370+
Examples:
371+
vulnetix vdb cloud-locators --vendor amazon --product s3 -V v2
372+
vulnetix vdb cloud-locators --vendor microsoft --product storage -V v2
373+
vulnetix vdb cloud-locators --vendor google --product compute -V v2
374+
vulnetix vdb cloud-locators --vendor cloudflare --product workers -V v2
375+
vulnetix vdb cloud-locators --vendor oracle --product compute -V v2
376+
vulnetix vdb cloud-locators --vendor amazon --product cloudfront -V v2 --output json`,
377+
RunE: func(cmd *cobra.Command, args []string) error {
378+
if err := requireV2("cloud-locators"); err != nil {
379+
return err
380+
}
381+
382+
vendor, _ := cmd.Flags().GetString("vendor")
383+
product, _ := cmd.Flags().GetString("product")
384+
385+
if vendor == "" && product == "" {
386+
return fmt.Errorf("at least one of --vendor or --product is required")
387+
}
388+
389+
client := newVDBClient()
390+
if vdbOutput == "json" {
391+
fmt.Fprintf(os.Stderr, "Fetching cloud locators for vendor=%s product=%s...\n", vendor, product)
392+
} else {
393+
fmt.Printf("Fetching cloud locators for vendor=%s product=%s...\n", vendor, product)
394+
}
395+
396+
result, err := client.V2CloudLocators(vendor, product)
397+
if err != nil {
398+
return fmt.Errorf("failed to get cloud locators: %w", err)
399+
}
400+
printRateLimit(client)
401+
return printOutput(result, vdbOutput)
402+
},
403+
}
404+
358405
// v2FixesMerged handles the -V v2 case for the fixes command by calling
359406
// all three V2 fix endpoints in parallel and merging the results.
360407
func v2FixesMerged(identifier string, cmd *cobra.Command) (map[string]interface{}, error) {
@@ -417,6 +464,11 @@ func init() {
417464
vdbCmd.AddCommand(v2AffectedCmd)
418465
vdbCmd.AddCommand(v2ScorecardCmd)
419466
vdbCmd.AddCommand(v2RemediationCmd)
467+
vdbCmd.AddCommand(v2CloudLocatorsCmd)
468+
469+
// Cloud locators flags
470+
v2CloudLocatorsCmd.Flags().String("vendor", "", "Vendor name (e.g. amazon, microsoft, google)")
471+
v2CloudLocatorsCmd.Flags().String("product", "", "Product/service name (e.g. s3, ec2, cloudfront)")
420472

421473
// CWE subcommands
422474
v2CweCmd.AddCommand(v2CweGuidanceCmd)

internal/purl/purl.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,42 @@ func (p *PackageURL) String() string {
150150
}
151151

152152
var ecosystemMap = map[string]string{
153-
"npm": "npm",
154-
"maven": "Maven",
155-
"pypi": "PyPI",
156-
"golang": "Go",
157-
"cargo": "crates.io",
158-
"nuget": "NuGet",
159-
"gem": "RubyGems",
160-
"composer": "Packagist",
161-
"swift": "SwiftURL",
162-
"cocoapods": "CocoaPods",
163-
"pub": "Pub",
164-
"hex": "Hex",
153+
"npm": "npm",
154+
"maven": "Maven",
155+
"pypi": "PyPI",
156+
"golang": "Go",
157+
"cargo": "crates.io",
158+
"nuget": "NuGet",
159+
"gem": "RubyGems",
160+
"composer": "Packagist",
161+
"swift": "SwiftURL",
162+
"cocoapods": "CocoaPods",
163+
"pub": "Pub",
164+
"hex": "Hex",
165+
"conda": "Conda",
166+
"conan": "Conan",
167+
"huggingface": "HuggingFace",
168+
"mlflow": "MLflow",
169+
"julia": "Julia",
170+
"luarocks": "LuaRocks",
171+
"opam": "opam",
172+
"cpan": "CPAN",
173+
"hackage": "Hackage",
174+
"cran": "CRAN",
175+
"yocto": "Yocto",
176+
"bitnami": "Bitnami",
177+
"bazel": "Bazel",
178+
"qpkg": "QPKG",
179+
"vscode-extension": "VSCode",
180+
"deb": "Debian",
181+
"rpm": "RPM",
182+
"apk": "Alpine",
183+
"alpm": "Arch Linux",
184+
"docker": "Docker",
185+
"oci": "OCI",
186+
"github": "GitHub",
187+
"bitbucket": "Bitbucket",
188+
"generic": "Generic",
165189
}
166190

167191
// EcosystemForType maps a PURL type to the VDB ecosystem name.

internal/vdb/api_v2.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,22 @@ func (c *Client) V2ScanStatus(scanID string) (map[string]interface{}, error) {
285285
return doV2Get(c, path)
286286
}
287287

288+
// V2CloudLocators retrieves cloud resource locator templates for a vendor/product pair.
289+
func (c *Client) V2CloudLocators(vendor, product string) (map[string]interface{}, error) {
290+
q := url.Values{}
291+
if vendor != "" {
292+
q.Set("vendor", vendor)
293+
}
294+
if product != "" {
295+
q.Set("product", product)
296+
}
297+
path := "/cloud-locators"
298+
if encoded := q.Encode(); encoded != "" {
299+
path += "?" + encoded
300+
}
301+
return doV2Get(c, path)
302+
}
303+
288304
func readFileBytes(filePath string) ([]byte, error) {
289305
data, err := os.ReadFile(filePath)
290306
if err != nil {

0 commit comments

Comments
 (0)