sprints work
This commit is contained in:
244
scripts/validate-sbom.sh
Normal file
244
scripts/validate-sbom.sh
Normal file
@@ -0,0 +1,244 @@
|
||||
#!/bin/bash
|
||||
# scripts/validate-sbom.sh
|
||||
# Sprint: SPRINT_8200_0001_0003 - SBOM Schema Validation in CI
|
||||
# Task: SCHEMA-8200-004 - Create validate-sbom.sh wrapper for sbom-utility
|
||||
#
|
||||
# Validates SBOM files against official CycloneDX JSON schemas.
|
||||
# Uses sbom-utility for CycloneDX validation.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/validate-sbom.sh <sbom-file> [--schema <schema-path>]
|
||||
# ./scripts/validate-sbom.sh bench/golden-corpus/sample.cyclonedx.json
|
||||
# ./scripts/validate-sbom.sh --all # Validate all CycloneDX fixtures
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 - All validations passed
|
||||
# 1 - Validation failed or error
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
SCHEMA_DIR="${REPO_ROOT}/docs/schemas"
|
||||
DEFAULT_SCHEMA="${SCHEMA_DIR}/cyclonedx-bom-1.6.schema.json"
|
||||
SBOM_UTILITY_VERSION="v0.16.0"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $*"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*"
|
||||
}
|
||||
|
||||
check_sbom_utility() {
|
||||
if ! command -v sbom-utility &> /dev/null; then
|
||||
log_warn "sbom-utility not found in PATH"
|
||||
log_info "Installing sbom-utility ${SBOM_UTILITY_VERSION}..."
|
||||
|
||||
# Detect OS and architecture
|
||||
local os arch
|
||||
case "$(uname -s)" in
|
||||
Linux*) os="linux";;
|
||||
Darwin*) os="darwin";;
|
||||
MINGW*|MSYS*|CYGWIN*) os="windows";;
|
||||
*) log_error "Unsupported OS: $(uname -s)"; exit 1;;
|
||||
esac
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) arch="amd64";;
|
||||
arm64|aarch64) arch="arm64";;
|
||||
*) log_error "Unsupported architecture: $(uname -m)"; exit 1;;
|
||||
esac
|
||||
|
||||
local url="https://github.com/CycloneDX/sbom-utility/releases/download/${SBOM_UTILITY_VERSION}/sbom-utility-${SBOM_UTILITY_VERSION}-${os}-${arch}.tar.gz"
|
||||
local temp_dir
|
||||
temp_dir=$(mktemp -d)
|
||||
|
||||
log_info "Downloading from ${url}..."
|
||||
curl -sSfL "${url}" | tar xz -C "${temp_dir}"
|
||||
|
||||
if [[ "$os" == "windows" ]]; then
|
||||
log_info "Please add ${temp_dir}/sbom-utility.exe to your PATH"
|
||||
export PATH="${temp_dir}:${PATH}"
|
||||
else
|
||||
log_info "Installing to /usr/local/bin (may require sudo)..."
|
||||
if [[ -w /usr/local/bin ]]; then
|
||||
mv "${temp_dir}/sbom-utility" /usr/local/bin/
|
||||
else
|
||||
sudo mv "${temp_dir}/sbom-utility" /usr/local/bin/
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf "${temp_dir}"
|
||||
log_info "sbom-utility installed successfully"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_cyclonedx() {
|
||||
local sbom_file="$1"
|
||||
local schema="${2:-$DEFAULT_SCHEMA}"
|
||||
|
||||
if [[ ! -f "$sbom_file" ]]; then
|
||||
log_error "File not found: $sbom_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$schema" ]]; then
|
||||
log_error "Schema not found: $schema"
|
||||
log_info "Expected schema at: ${DEFAULT_SCHEMA}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detect if it's a CycloneDX file
|
||||
if ! grep -q '"bomFormat"' "$sbom_file" 2>/dev/null; then
|
||||
log_warn "File does not appear to be CycloneDX: $sbom_file"
|
||||
log_info "Skipping (use validate-spdx.sh for SPDX files)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Validating: $sbom_file"
|
||||
|
||||
# Run sbom-utility validation
|
||||
if sbom-utility validate --input-file "$sbom_file" --format json 2>&1; then
|
||||
log_info "✓ Validation passed: $sbom_file"
|
||||
return 0
|
||||
else
|
||||
log_error "✗ Validation failed: $sbom_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_all() {
|
||||
local fixture_dir="${REPO_ROOT}/bench/golden-corpus"
|
||||
local failed=0
|
||||
local passed=0
|
||||
local skipped=0
|
||||
|
||||
log_info "Validating all CycloneDX fixtures in ${fixture_dir}..."
|
||||
|
||||
if [[ ! -d "$fixture_dir" ]]; then
|
||||
log_error "Fixture directory not found: $fixture_dir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
while IFS= read -r -d '' file; do
|
||||
if grep -q '"bomFormat".*"CycloneDX"' "$file" 2>/dev/null; then
|
||||
if validate_cyclonedx "$file"; then
|
||||
((passed++))
|
||||
else
|
||||
((failed++))
|
||||
fi
|
||||
else
|
||||
log_info "Skipping non-CycloneDX file: $file"
|
||||
((skipped++))
|
||||
fi
|
||||
done < <(find "$fixture_dir" -type f -name '*.json' -print0)
|
||||
|
||||
echo ""
|
||||
log_info "Validation Summary:"
|
||||
log_info " Passed: ${passed}"
|
||||
log_info " Failed: ${failed}"
|
||||
log_info " Skipped: ${skipped}"
|
||||
|
||||
if [[ $failed -gt 0 ]]; then
|
||||
log_error "Some validations failed!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "All CycloneDX validations passed!"
|
||||
return 0
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") [OPTIONS] <sbom-file>
|
||||
|
||||
Validates CycloneDX SBOM files against official JSON schemas.
|
||||
|
||||
Options:
|
||||
--all Validate all CycloneDX fixtures in bench/golden-corpus/
|
||||
--schema <path> Use custom schema file (default: docs/schemas/cyclonedx-bom-1.6.schema.json)
|
||||
--help, -h Show this help message
|
||||
|
||||
Examples:
|
||||
$(basename "$0") sample.cyclonedx.json
|
||||
$(basename "$0") --schema custom-schema.json sample.json
|
||||
$(basename "$0") --all
|
||||
|
||||
Exit codes:
|
||||
0 All validations passed
|
||||
1 Validation failed or error
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
local schema="$DEFAULT_SCHEMA"
|
||||
local validate_all_flag=false
|
||||
local files=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--all)
|
||||
validate_all_flag=true
|
||||
shift
|
||||
;;
|
||||
--schema)
|
||||
schema="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
files+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Ensure sbom-utility is available
|
||||
check_sbom_utility
|
||||
|
||||
if [[ "$validate_all_flag" == "true" ]]; then
|
||||
validate_all
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ ${#files[@]} -eq 0 ]]; then
|
||||
log_error "No SBOM file specified"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local failed=0
|
||||
for file in "${files[@]}"; do
|
||||
if ! validate_cyclonedx "$file" "$schema"; then
|
||||
((failed++))
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $failed -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user