Validation
The CPE library provides validation, format-detection, and normalization functions to ensure CPE data integrity and compliance with CPE specifications.
The diagram below shows the validation pipeline, from single-field component checks up through whole-CPE validation, format detection, and normalization:
Component Validation
ValidateComponent
func ValidateComponent(value string, componentName string) errorValidates a single CPE component value (vendor, product, version, etc.) for compliance with CPE naming rules.
Parameters:
value- Component value to validatecomponentName- Name of the component (used in the error message to identify which field failed)
Returns:
error- Error if validation fails,nilif valid
Validation Rules:
- Empty strings are treated as valid (wildcard)
- Special values
*(ANY) and-(NA) are allowed - Must not contain illegal characters (
! @ # $ % ^ & ( ) { } [ ] | \ ; " ' < > ?) - Must not contain control characters or characters outside the printable ASCII range (32–126)
Example:
// Valid components
err := cpeskills.ValidateComponent("microsoft", "Vendor")
if err != nil {
fmt.Printf("Invalid: %v\n", err)
} else {
fmt.Println("Valid component")
}
// Special values
err = cpeskills.ValidateComponent("*", "Version") // ANY value
if err == nil {
fmt.Println("Wildcard is valid")
}
err = cpeskills.ValidateComponent("-", "Version") // NA value
if err == nil {
fmt.Println("NA value is valid")
}
// Invalid component with a control character
err = cpeskills.ValidateComponent("invalid\x00component", "Product")
if err != nil {
fmt.Printf("Invalid component: %v\n", err)
}CPE Validation
ValidateCPE
func ValidateCPE(cpe *CPE) errorValidates a complete CPE object for correctness and compliance.
Parameters:
cpe- CPE object to validate
Returns:
error- Error if validation fails
Validation Checks:
cpemust not benilPartmust not be empty and must be one ofa,h,o, or*VendorandProductNamemust not be empty- Every component field is passed through
ValidateComponent
Example:
// Create and validate a CPE
cpeObj := &cpeskills.CPE{
Part: *cpeskills.PartApplication,
Vendor: cpeskills.Vendor("microsoft"),
ProductName: cpeskills.Product("windows"),
Version: cpeskills.Version("10"),
}
err := cpeskills.ValidateCPE(cpeObj)
if err != nil {
fmt.Printf("CPE validation failed: %v\n", err)
} else {
fmt.Println("CPE is valid")
}
// Test invalid CPE
invalidCPE := &cpeskills.CPE{
Part: cpeskills.Part{ShortName: "x"}, // Invalid part
Vendor: cpeskills.Vendor("microsoft"),
ProductName: cpeskills.Product("windows"),
}
err = cpeskills.ValidateCPE(invalidCPE)
if err != nil {
fmt.Printf("Expected validation error: %v\n", err)
}Format Detection
IsCPE23String
func IsCPE23String(s string) boolReports whether a string looks like a CPE 2.3 URI (i.e. it starts with cpe:2.3:).
Parameters:
s- String to check
Returns:
bool-trueif the string is in CPE 2.3 form
Example:
cpe23Examples := []string{
"cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*", // CPE 2.3
"cpe:/a:apache:tomcat:8.5.0", // CPE 2.2
"not a cpe", // Not a CPE
}
for _, example := range cpe23Examples {
if cpeskills.IsCPE23String(example) {
fmt.Printf("CPE 2.3 string: %s\n", example)
} else {
fmt.Printf("Not a CPE 2.3 string: %s\n", example)
}
}IsCPE22String
func IsCPE22String(s string) boolReports whether a string looks like a CPE 2.2 URI (i.e. it starts with cpe:/).
Parameters:
s- String to check
Returns:
bool-trueif the string is in CPE 2.2 form
Example:
cpe22Examples := []string{
"cpe:/a:apache:tomcat:8.5.0", // CPE 2.2
"cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*", // CPE 2.3
"invalid:/a:apache:tomcat:8.5.0", // Invalid prefix
}
for _, example := range cpe22Examples {
if cpeskills.IsCPE22String(example) {
fmt.Printf("CPE 2.2 string: %s\n", example)
} else {
fmt.Printf("Not a CPE 2.2 string: %s\n", example)
}
}Normalization
NormalizeComponent
func NormalizeComponent(value string) stringNormalizes a CPE component according to CPE specification rules.
Parameters:
value- Component to normalize
Returns:
string- Normalized component
Normalization Rules:
- Special values (
*,-, and the empty string) are returned unchanged - Convert to lowercase
- Replace spaces with underscores
- Collapse repeated underscores into a single underscore
Example:
// Test component normalization
components := []string{
"Microsoft", // -> "microsoft"
"Windows 10", // -> "windows_10"
"Microsoft Office", // -> "microsoft_office"
"*", // -> "*" (unchanged)
"-", // -> "-" (unchanged)
}
for _, comp := range components {
normalized := cpeskills.NormalizeComponent(comp)
fmt.Printf("'%s' -> '%s'\n", comp, normalized)
}NormalizeCPE
func NormalizeCPE(cpe *CPE) *CPENormalizes all components of a CPE object. The input object is left unchanged; a new normalized object is returned (or nil if the input is nil).
Parameters:
cpe- CPE to normalize
Returns:
*CPE- New CPE with normalized components
Example:
// Create CPE with non-normalized components
originalCPE := &cpeskills.CPE{
Part: *cpeskills.PartApplication,
Vendor: cpeskills.Vendor("Microsoft"),
ProductName: cpeskills.Product("Windows 10"),
Version: cpeskills.Version("1.0"),
}
// Normalize the CPE
normalizedCPE := cpeskills.NormalizeCPE(originalCPE)
fmt.Printf("Original vendor: %s\n", originalCPE.Vendor)
fmt.Printf("Normalized vendor: %s\n", normalizedCPE.Vendor)
fmt.Printf("Original product: %s\n", originalCPE.ProductName)
fmt.Printf("Normalized product: %s\n", normalizedCPE.ProductName)Complete Example
package main
import (
"fmt"
"github.com/scagogogo/cpe-skills"
)
func main() {
// Component validation
fmt.Println("=== Component Validation ===")
components := []string{
"microsoft", // Valid
"windows_10", // Valid
"*", // Valid (wildcard)
"-", // Valid (NA)
"invalid\x00", // Invalid (control character)
}
for _, comp := range components {
err := cpeskills.ValidateComponent(comp, "Component")
if err != nil {
fmt.Printf("Invalid component '%s': %v\n", comp, err)
} else {
fmt.Printf("Valid component: %s\n", comp)
}
}
// Format detection
fmt.Println("\n=== Format Detection ===")
cpeStrings := []string{
"cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*",
"cpe:/a:apache:tomcat:8.5.0",
"invalid:format",
}
for _, cpeStr := range cpeStrings {
switch {
case cpeskills.IsCPE23String(cpeStr):
fmt.Printf("CPE 2.3 string: %s\n", cpeStr)
case cpeskills.IsCPE22String(cpeStr):
fmt.Printf("CPE 2.2 string: %s\n", cpeStr)
default:
fmt.Printf("Not a CPE string: %s\n", cpeStr)
}
}
// CPE object validation
fmt.Println("\n=== CPE Object Validation ===")
validCPE := &cpeskills.CPE{
Part: *cpeskills.PartApplication,
Vendor: cpeskills.Vendor("microsoft"),
ProductName: cpeskills.Product("windows"),
Version: cpeskills.Version("10"),
}
err := cpeskills.ValidateCPE(validCPE)
if err != nil {
fmt.Printf("CPE validation failed: %v\n", err)
} else {
fmt.Println("CPE object is valid")
}
// Component normalization
fmt.Println("\n=== Component Normalization ===")
unnormalizedComponents := []string{
"Microsoft",
"Windows 10",
"Microsoft Office",
"Product Name",
}
for _, comp := range unnormalizedComponents {
normalized := cpeskills.NormalizeComponent(comp)
fmt.Printf("'%s' -> '%s'\n", comp, normalized)
}
// CPE normalization
fmt.Println("\n=== CPE Normalization ===")
unnormalizedCPE := &cpeskills.CPE{
Part: *cpeskills.PartApplication,
Vendor: cpeskills.Vendor("Microsoft"),
ProductName: cpeskills.Product("Windows 10"),
Version: cpeskills.Version("1.0"),
}
normalizedCPE := cpeskills.NormalizeCPE(unnormalizedCPE)
fmt.Printf("Original: %s %s %s\n",
unnormalizedCPE.Vendor, unnormalizedCPE.ProductName, unnormalizedCPE.Version)
fmt.Printf("Normalized: %s %s %s\n",
normalizedCPE.Vendor, normalizedCPE.ProductName, normalizedCPE.Version)
}