From 20a6e5397d8b1bb51b752303756f3f84626c6951 Mon Sep 17 00:00:00 2001 From: woojae-siloai Date: Fri, 9 Jan 2026 16:43:57 +0200 Subject: [PATCH 1/3] feat: implement modular SBOM validation system --- .../workflows/pr-component-validation.yaml | 101 +---------------- sbom/components.yaml | 12 +- sbom/generate-compare-components.sh | 81 +++++++++++--- sbom/validate-components-sync.sh | 105 ++++++++++++++++++ sbom/validate-enabled-apps.sh | 72 ++++++++++++ sbom/validate-metadata.sh | 91 +++++++++++++++ sbom/validate-sync.sh | 30 +++++ 7 files changed, 379 insertions(+), 113 deletions(-) create mode 100755 sbom/validate-components-sync.sh create mode 100755 sbom/validate-enabled-apps.sh create mode 100755 sbom/validate-metadata.sh create mode 100755 sbom/validate-sync.sh diff --git a/.github/workflows/pr-component-validation.yaml b/.github/workflows/pr-component-validation.yaml index 6b6e2439..d162e8c9 100644 --- a/.github/workflows/pr-component-validation.yaml +++ b/.github/workflows/pr-component-validation.yaml @@ -3,11 +3,11 @@ name: PR Component Validation on: workflow_dispatch: pull_request: - branches: [ main ] + branches: [ main, update_sbom_workflow ] paths: - 'sbom/components.yaml' - 'root/values.yaml' - - 'sbom/generate-compare-components.sh' + - 'sbom/*.sh' jobs: validate-components: @@ -22,99 +22,8 @@ jobs: sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 sudo chmod +x /usr/local/bin/yq - - name: Run generate-compare-components.sh + - name: Validate SBOM Sync (Gatekeeper) working-directory: ./sbom run: | - chmod +x generate-compare-components.sh - ./generate-compare-components.sh - - - name: Validate component URLs - working-directory: ./sbom - run: | - echo "Validating components.yaml for missing sourceUrl and projectUrl..." - - # Check if components.yaml exists - if [[ ! -f "components.yaml" ]]; then - echo "❌ Error: components.yaml not found" - exit 1 - fi - - # Get all component names - component_names=$(yq eval '.components | keys | .[]' components.yaml) - - missing_fields=false - missing_components=() - - # Check each component for missing fields - for component in $component_names; do - source_url=$(yq eval ".components.\"$component\".sourceUrl // \"\"" components.yaml) - project_url=$(yq eval ".components.\"$component\".projectUrl // \"\"" components.yaml) - license=$(yq eval ".components.\"$component\".license // \"\"" components.yaml) - license_url=$(yq eval ".components.\"$component\".licenseUrl // \"\"" components.yaml) - - component_missing=false - - if [[ -z "$source_url" ]]; then - echo "❌ Missing sourceUrl for component: $component" - missing_fields=true - component_missing=true - fi - - if [[ -z "$project_url" ]]; then - echo "❌ Missing projectUrl for component: $component" - missing_fields=true - component_missing=true - fi - - if [[ -z "$license" ]]; then - echo "❌ Missing license for component: $component" - missing_fields=true - component_missing=true - fi - - if [[ -z "$license_url" ]]; then - echo "❌ Missing licenseUrl for component: $component" - missing_fields=true - component_missing=true - fi - - if [[ "$component_missing" == true ]]; then - missing_components+=("$component") - else - echo "✅ Component $component has all required fields (sourceUrl, projectUrl, license, licenseUrl)" - fi - done - - if [[ "$missing_fields" == true ]]; then - echo "" - echo "❌ VALIDATION FAILED!" - echo "The following components are missing required fields:" - for comp in "${missing_components[@]}"; do - echo " - $comp" - done - echo "" - echo "Please ensure all components have 'sourceUrl', 'projectUrl', 'license', and 'licenseUrl' populated in components.yaml" - echo "" - echo "📝 Manual steps required:" - echo " 1. Fill in 'sourceUrl' and 'projectUrl' manually for missing components" - echo " 2. Run ./update_licenses.sh to auto-populate license fields from GitHub" - echo "" - echo "💡 Note: 'sourceUrl' and 'projectUrl' must be provided manually as they require" - echo " human knowledge about where to find charts/manifests and project repositories." - exit 1 - else - echo "" - echo "✅ All components have required fields (sourceUrl, projectUrl, license, licenseUrl)!" - fi - - - name: Check for uncommitted changes - working-directory: ./sbom - run: | - if [[ -n $(git status --porcelain components.yaml) ]]; then - echo "❌ components.yaml has uncommitted changes after running generate-compare-components.sh" - echo "Please commit the updated components.yaml file" - git diff components.yaml - exit 1 - else - echo "✅ components.yaml is up to date" - fi \ No newline at end of file + chmod +x validate-*.sh + ./validate-sync.sh \ No newline at end of file diff --git a/sbom/components.yaml b/sbom/components.yaml index 236cc828..35fdcadd 100644 --- a/sbom/components.yaml +++ b/sbom/components.yaml @@ -1,8 +1,14 @@ # Generated components metadata for SBOM creation -# This file contains simplified component information extracted from values.yaml -# Apps with "config" suffix are excluded +# This file contains simplified component information for apps in enabledApps +# Apps with "config" suffix are excluded from this SBOM components: + aim-cluster-model-source: + path: aim-cluster-model-source + sourceUrl: https://github.com/silogen/kaiwo/releases/download/v0.2.0-rc11/crds.yaml + projectUrl: https://github.com/silogen/kaiwo/ + license: MIT License + licenseUrl: https://github.com/silogen/kaiwo/blob/main/LICENSE argocd: path: argocd/8.3.5 valuesFile: ../values_cf.yaml @@ -190,7 +196,7 @@ components: kaiwo-crds: path: kaiwo-crds/v0.2.0-rc11 sourceUrl: https://github.com/silogen/kaiwo/releases/download/v0.2.0-rc11/crds.yaml - projectUrl: //github.com/silogen/kaiwo/ + projectUrl: https://github.com/silogen/kaiwo/ license: MIT License licenseUrl: https://github.com/silogen/kaiwo/blob/main/LICENSE kaiwo: diff --git a/sbom/generate-compare-components.sh b/sbom/generate-compare-components.sh index 5d1190a5..26644d5e 100755 --- a/sbom/generate-compare-components.sh +++ b/sbom/generate-compare-components.sh @@ -2,24 +2,64 @@ set -euo pipefail -# Script to update components.yaml from values.yaml +# Script to update components.yaml from enabledApps in values.yaml # Only updates if there are new items or changes to existing ones # Preserves existing sourceUrl and projectUrl values +# Only includes apps that are in the enabledApps list (excluding -config apps) VALUES_FILE="../root/values.yaml" OUTPUT_FILE="./components.yaml" TEMP_FILE="./components.yaml.tmp" +echo "⚙️ Generating/Updating components.yaml from enabledApps..." + +# Self-validation: Check enabledApps consistency before processing (fail-fast) +echo "🔍 Pre-validation: Checking enabledApps consistency..." +if [[ -f "./validate-enabled-apps.sh" ]]; then + if ! ./validate-enabled-apps.sh; then + echo "" + echo "❌ Pre-validation failed! Cannot generate components.yaml with invalid enabledApps." + echo "Please fix the enabledApps issues above before running generation." + exit 1 + fi + echo "✅ Pre-validation passed - proceeding with generation..." +else + echo "⚠️ Warning: validate-enabled-apps.sh not found, skipping pre-validation" +fi + +echo "" echo "Checking for updates to components.yaml..." # Check if values.yaml exists if [[ ! -f "$VALUES_FILE" ]]; then - echo "Error: $VALUES_FILE not found" + echo "❌ Error: $VALUES_FILE not found" exit 1 fi -# Get all app names that don't end with -config from values.yaml -app_names=$(yq eval '.apps | keys | .[] | select(. | test("-config$") | not)' "$VALUES_FILE") +# Get all enabled app names that don't end with -config from values.yaml +enabled_apps=$(yq eval '.enabledApps[]' "$VALUES_FILE" 2>/dev/null || echo "") + +if [[ -z "$enabled_apps" ]]; then + echo "Warning: No enabled apps found in enabledApps list" + if [[ -f "$OUTPUT_FILE" ]]; then + backup_file="./components-old-$(date +%Y%m%d-%H%M%S).yaml" + echo "Backing up existing $OUTPUT_FILE to $backup_file" + mv "$OUTPUT_FILE" "$backup_file" + fi + exit 0 +fi + +app_names=$(echo "$enabled_apps" | grep -v -- '-config$' || echo "") + +if [[ -z "$app_names" ]]; then + echo "Warning: No non-config apps found in enabledApps list" + if [[ -f "$OUTPUT_FILE" ]]; then + backup_file="./components-old-$(date +%Y%m%d-%H%M%S).yaml" + echo "Backing up existing $OUTPUT_FILE to $backup_file (only config apps enabled)" + mv "$OUTPUT_FILE" "$backup_file" + fi + exit 0 +fi # Check if components.yaml exists if [[ ! -f "$OUTPUT_FILE" ]]; then @@ -29,9 +69,9 @@ else echo "Existing $OUTPUT_FILE found. Checking for changes..." needs_update=false - # Check each app from values.yaml + # Check each enabled app from values.yaml for app in $app_names; do - # Get current values from values.yaml + # Get current values from values.yaml apps section current_path=$(yq eval ".apps.\"$app\".path" "$VALUES_FILE") current_values_file=$(yq eval ".apps.\"$app\".valuesFile // \"null\"" "$VALUES_FILE") @@ -61,12 +101,12 @@ else fi done - # Check for removed apps (apps in components.yaml that are no longer in values.yaml) + # Check for removed apps (apps in components.yaml that are no longer in enabledApps) if [[ "$needs_update" == "false" ]]; then - existing_components=$(yq eval '.components | keys | .[]' "$OUTPUT_FILE") + existing_components=$(yq eval '.components | keys | .[]' "$OUTPUT_FILE" 2>/dev/null || echo "") for existing_component in $existing_components; do if ! echo "$app_names" | grep -q "^$existing_component$"; then - echo " Removed app found: $existing_component" + echo " Removed app found: $existing_component (no longer in enabledApps)" needs_update=true break fi @@ -84,8 +124,8 @@ echo "Updating $OUTPUT_FILE..." # Create components.yaml header cat > "$TEMP_FILE" << 'EOF' # Generated components metadata for SBOM creation -# This file contains simplified component information extracted from values.yaml -# Apps with "config" suffix are excluded +# This file contains simplified component information for apps in enabledApps +# Apps with "config" suffix are excluded from this SBOM components: EOF @@ -146,9 +186,9 @@ done # Replace the original file mv "$TEMP_FILE" "$OUTPUT_FILE" -echo "Updated $OUTPUT_FILE successfully" +echo "✅ Updated $OUTPUT_FILE successfully" echo "" -echo "Summary of components:" +echo "📊 Summary of components:" echo "$app_names" | wc -l | xargs echo "Total components:" echo "" echo "Components with valuesFile:" @@ -157,4 +197,17 @@ for app in $app_names; do if [[ "$values_file" != "null" ]]; then echo " - $app" fi -done \ No newline at end of file +done + +echo "" +echo "✅ Components generated/updated successfully!" +echo "" +echo "📝 Next steps:" +echo " 1. Fill in 'sourceUrl' and 'projectUrl' for any components with empty values" +echo " 2. Run ./update_licenses.sh to auto-populate license fields from GitHub" +echo " 3. Run ./validate-sync.sh to verify everything is ready for commit" +echo "" +echo "💡 Tip: Use individual validation scripts for targeted debugging:" +echo " - ./validate-enabled-apps.sh (check app definitions)" +echo " - ./validate-components-sync.sh (check sync status)" +echo " - ./validate-metadata.sh (check required fields)" \ No newline at end of file diff --git a/sbom/validate-components-sync.sh b/sbom/validate-components-sync.sh new file mode 100755 index 00000000..476e1e15 --- /dev/null +++ b/sbom/validate-components-sync.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +set -euo pipefail + +# validate-components-sync.sh - Validate components.yaml sync with enabledApps +# Checks that components.yaml reflects current enabledApps and path consistency + +VALUES_FILE="../root/values.yaml" +COMPONENTS_FILE="./components.yaml" + +echo "🔄 Validating components.yaml reflects enabledApps..." + +# Check if components.yaml exists +if [[ ! -f "$COMPONENTS_FILE" ]]; then + echo "❌ Error: $COMPONENTS_FILE not found" + echo "Please run ./generate-compare-components.sh to create components.yaml" + exit 1 +fi + +# Check if values.yaml exists +if [[ ! -f "$VALUES_FILE" ]]; then + echo "❌ Error: $VALUES_FILE not found" + exit 1 +fi + +# Get enabled apps (filtered, same as generation script) +enabled_apps=$(yq eval '.enabledApps[]' "$VALUES_FILE" 2>/dev/null || echo "") +enabled_apps_filtered=$(echo "$enabled_apps" | grep -v -- '-config$' || echo "") + +# Get components in components.yaml +existing_components=$(yq eval '.components | keys | .[]' "$COMPONENTS_FILE" 2>/dev/null || echo "") + +# Check for missing components (in enabledApps but not in components.yaml) +missing_components=() +while IFS= read -r app; do + [[ -z "$app" ]] && continue + if ! echo "$existing_components" | grep -q "^$app$"; then + missing_components+=("$app") + echo "❌ Component missing: '$app' is enabled but not in components.yaml" + fi +done <<< "$enabled_apps_filtered" + +# Check for extra components (in components.yaml but not in enabledApps) +extra_components=() +while IFS= read -r component; do + [[ -z "$component" ]] && continue + if ! echo "$enabled_apps_filtered" | grep -q "^$component$"; then + extra_components+=("$component") + echo "❌ Component extra: '$component' is in components.yaml but not enabled" + fi +done <<< "$existing_components" + +if [ ${#missing_components[@]} -ne 0 ] || [ ${#extra_components[@]} -ne 0 ]; then + echo "" + echo "❌ COMPONENTS SYNC FAILED!" + if [ ${#missing_components[@]} -ne 0 ]; then + echo "Missing components (run ./generate-compare-components.sh):" + printf ' - %s\n' "${missing_components[@]}" + fi + if [ ${#extra_components[@]} -ne 0 ]; then + echo "Extra components (remove from enabledApps or regenerate):" + printf ' - %s\n' "${extra_components[@]}" + fi + echo "" + echo "📝 Required action: Run ./generate-compare-components.sh to sync components.yaml" + exit 1 +fi + +# Check path consistency between values.yaml and components.yaml +echo "⚙️ Checking path/valuesFile consistency..." +path_mismatches=() + +while IFS= read -r app; do + [[ -z "$app" ]] && continue + + # Get paths from both files + values_path=$(yq eval ".apps.\"$app\".path" "$VALUES_FILE" 2>/dev/null || echo "null") + component_path=$(yq eval ".components.\"$app\".path" "$COMPONENTS_FILE" 2>/dev/null || echo "null") + + if [[ "$values_path" != "$component_path" ]]; then + path_mismatches+=("$app: values.yaml='$values_path' vs components.yaml='$component_path'") + echo "❌ Path mismatch for '$app': values.yaml='$values_path' vs components.yaml='$component_path'" + fi + + # Check valuesFile consistency + values_file_values=$(yq eval ".apps.\"$app\".valuesFile // \"null\"" "$VALUES_FILE" 2>/dev/null || echo "null") + values_file_components=$(yq eval ".components.\"$app\".valuesFile // \"null\"" "$COMPONENTS_FILE" 2>/dev/null || echo "null") + + if [[ "$values_file_values" != "$values_file_components" ]]; then + path_mismatches+=("$app valuesFile: values.yaml='$values_file_values' vs components.yaml='$values_file_components'") + echo "❌ ValuesFile mismatch for '$app': values.yaml='$values_file_values' vs components.yaml='$values_file_components'" + fi +done <<< "$enabled_apps_filtered" + +if [ ${#path_mismatches[@]} -ne 0 ]; then + echo "" + echo "❌ PATH/CONFIG SYNC FAILED!" + echo "Path/configuration mismatches found:" + printf ' - %s\n' "${path_mismatches[@]}" + echo "" + echo "📝 Required action: Run ./generate-compare-components.sh to sync path/valuesFile information" + exit 1 +fi + +echo "✅ Components.yaml is properly synced with enabledApps" \ No newline at end of file diff --git a/sbom/validate-enabled-apps.sh b/sbom/validate-enabled-apps.sh new file mode 100755 index 00000000..53a78685 --- /dev/null +++ b/sbom/validate-enabled-apps.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +set -euo pipefail + +# validate-enabled-apps.sh - Validate enabledApps consistency +# Checks that all apps in enabledApps have corresponding definitions in apps section + +VALUES_FILE="../root/values.yaml" + +echo "📋 Validating enabledApps have app definitions..." + +# Check if values.yaml exists +if [[ ! -f "$VALUES_FILE" ]]; then + echo "❌ Error: $VALUES_FILE not found" + exit 1 +fi + +# Get all enabled apps +enabled_apps=$(yq eval '.enabledApps[]' "$VALUES_FILE" 2>/dev/null || echo "") + +if [[ -z "$enabled_apps" ]]; then + echo "ℹ️ No enabled apps found in enabledApps list" + exit 0 +fi + +# Filter out apps that end with -config (same logic as generate script) +enabled_apps_filtered=$(echo "$enabled_apps" | grep -v -- '-config$' || echo "") + +if [[ -z "$enabled_apps_filtered" ]]; then + echo "ℹ️ No non-config apps found in enabledApps list" + exit 0 +fi + +# Get all defined apps in apps section +defined_apps=$(yq eval '.apps | keys | .[]' "$VALUES_FILE" 2>/dev/null || echo "") + +if [[ -z "$defined_apps" ]]; then + echo "❌ Error: No app definitions found in apps section" + exit 1 +fi + +missing_apps=() + +# Check each enabled app has a definition +while IFS= read -r app; do + [[ -z "$app" ]] && continue + + if ! echo "$defined_apps" | grep -q "^$app$"; then + missing_apps+=("$app") + echo "❌ Enabled app '$app' has no definition in apps section" + else + echo "✅ App '$app' is properly defined" + fi +done <<< "$enabled_apps_filtered" + +if [ ${#missing_apps[@]} -ne 0 ]; then + echo "" + echo "❌ VALIDATION FAILED!" + echo "The following apps are enabled but have no app definitions:" + printf ' - %s\n' "${missing_apps[@]}" + echo "" + echo "Please add app definitions for these components in the apps section of values.yaml" + echo "" + echo "📝 Required action:" + echo " Add definitions in the 'apps:' section for each missing app with required fields:" + echo " - path: (path to helm chart or manifest)" + echo " - namespace: (target namespace)" + echo " - Other app-specific configuration as needed" + exit 1 +else + echo "✅ All enabled apps have corresponding definitions in the apps section" +fi \ No newline at end of file diff --git a/sbom/validate-metadata.sh b/sbom/validate-metadata.sh new file mode 100755 index 00000000..91589254 --- /dev/null +++ b/sbom/validate-metadata.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +set -euo pipefail + +# validate-metadata.sh - Validate component metadata completeness +# Checks that all components have required metadata fields populated + +COMPONENTS_FILE="./components.yaml" + +echo "📝 Validating required metadata fields are populated..." + +# Check if components.yaml exists +if [[ ! -f "$COMPONENTS_FILE" ]]; then + echo "❌ Error: $COMPONENTS_FILE not found" + echo "Please run ./generate-compare-components.sh to create components.yaml" + exit 1 +fi + +# Get all component names +component_names=$(yq eval '.components | keys | .[]' "$COMPONENTS_FILE" 2>/dev/null || echo "") + +if [[ -z "$component_names" ]]; then + echo "ℹ️ No components found in components.yaml" + exit 0 +fi + +missing_fields=false +missing_components=() + +# Check each component for missing fields +while IFS= read -r component; do + [[ -z "$component" ]] && continue + + source_url=$(yq eval ".components.\"$component\".sourceUrl // \"\"" "$COMPONENTS_FILE") + project_url=$(yq eval ".components.\"$component\".projectUrl // \"\"" "$COMPONENTS_FILE") + license=$(yq eval ".components.\"$component\".license // \"\"" "$COMPONENTS_FILE") + license_url=$(yq eval ".components.\"$component\".licenseUrl // \"\"" "$COMPONENTS_FILE") + + component_missing=false + + if [[ -z "$source_url" ]]; then + echo "❌ Missing sourceUrl for component: $component" + missing_fields=true + component_missing=true + fi + + if [[ -z "$project_url" ]]; then + echo "❌ Missing projectUrl for component: $component" + missing_fields=true + component_missing=true + fi + + if [[ -z "$license" ]]; then + echo "❌ Missing license for component: $component" + missing_fields=true + component_missing=true + fi + + if [[ -z "$license_url" ]]; then + echo "❌ Missing licenseUrl for component: $component" + missing_fields=true + component_missing=true + fi + + if [[ "$component_missing" == true ]]; then + missing_components+=("$component") + else + echo "✅ Component $component has all required fields" + fi +done <<< "$component_names" + +if [[ "$missing_fields" == true ]]; then + echo "" + echo "❌ METADATA VALIDATION FAILED!" + echo "The following components are missing required fields:" + for comp in "${missing_components[@]}"; do + echo " - $comp" + done + echo "" + echo "Please ensure all components have 'sourceUrl', 'projectUrl', 'license', and 'licenseUrl' populated in components.yaml" + echo "" + echo "📝 Manual steps required:" + echo " 1. Fill in 'sourceUrl' and 'projectUrl' manually for missing components" + echo " 2. Run ./update_licenses.sh to auto-populate license fields from GitHub" + echo "" + echo "💡 Note: 'sourceUrl' and 'projectUrl' must be provided manually as they require" + echo " human knowledge about where to find charts/manifests and project repositories." + exit 1 +else + echo "✅ All components have required metadata fields populated" +fi \ No newline at end of file diff --git a/sbom/validate-sync.sh b/sbom/validate-sync.sh new file mode 100755 index 00000000..c6b6b673 --- /dev/null +++ b/sbom/validate-sync.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -euo pipefail + +# validate-sync.sh - Comprehensive SBOM sync validator +# Orchestrates all validation checks to ensure values.yaml and components.yaml are in sync +# Used by both human developers and CI/CD workflow + +echo "🛡️ SBOM Sync Validation" +echo "Running comprehensive validation checks..." +echo "" + +# Run individual validation scripts in sequence +echo "Step 1/3: EnabledApps Consistency Check" +./validate-enabled-apps.sh + +echo "" +echo "Step 2/3: Components Sync Check" +./validate-components-sync.sh + +echo "" +echo "Step 3/3: Metadata Completeness Check" +./validate-metadata.sh + +echo "" +echo "🎉 SUCCESS! All SBOM sync validations passed!" +echo "✅ values.yaml and components.yaml are properly synchronized" +echo "✅ All required metadata fields are populated" +echo "" +echo "Your changes are ready for commit and PR!" \ No newline at end of file From 666d0db30f92823679bbf41399bc2f4f4c6201e1 Mon Sep 17 00:00:00 2001 From: woojae-siloai Date: Fri, 9 Jan 2026 17:17:03 +0200 Subject: [PATCH 2/3] feat: implement modular SBOM validation system --- .github/workflows/pr-component-validation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-component-validation.yaml b/.github/workflows/pr-component-validation.yaml index d162e8c9..ee6f6b92 100644 --- a/.github/workflows/pr-component-validation.yaml +++ b/.github/workflows/pr-component-validation.yaml @@ -3,7 +3,7 @@ name: PR Component Validation on: workflow_dispatch: pull_request: - branches: [ main, update_sbom_workflow ] + branches: [ main ] paths: - 'sbom/components.yaml' - 'root/values.yaml' From ddffd2af5bca3724c2a056df2a9dfbfb53c2ae4c Mon Sep 17 00:00:00 2001 From: woojae-siloai Date: Tue, 13 Jan 2026 16:22:54 +0200 Subject: [PATCH 3/3] docs: restructure quick guide for new modular validation system --- sbom/SBOM-QUICK-GUIDE.md | 105 +++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 10 deletions(-) diff --git a/sbom/SBOM-QUICK-GUIDE.md b/sbom/SBOM-QUICK-GUIDE.md index 1187d890..bc007fd5 100644 --- a/sbom/SBOM-QUICK-GUIDE.md +++ b/sbom/SBOM-QUICK-GUIDE.md @@ -2,27 +2,112 @@ Scripts to manage component metadata for automated Software Bill of Materials (SBOM) generation. +## Essential Workflow + +When `root/values.yaml` has a new tool, you need to run these commands manually: + +```bash +# 1. Generate/sync components from enabledApps +./generate-compare-components.sh + +# 2. Manually fill out sourceUrl and projectUrl in components.yaml +# (requires human knowledge about chart/manifest locations) + +# 3. Auto-populate license information +./update_licenses.sh + +# 4. Validate everything is ready +./validate-sync.sh +``` + ## Quick Start -1. **Add new component**: Update `values.yaml` → run `./generate-compare-components.sh` → manually add sourceUrl and projectUrl to `components.yaml` → run `./update_licenses.sh` -2. **Remove component**: Remove from `values.yaml` → run `./generate-compare-components.sh` +### Adding a New Component +1. **Update values.yaml**: Add to `enabledApps` list AND add app definition in `apps` section +2. **Run workflow**: Execute the 4 commands above +3. **Commit changes**: All files should be ready for PR + +### Removing a Component +1. **Remove from enabledApps**: Remove from `enabledApps` list in `root/values.yaml` +2. **Regenerate**: Run `./generate-compare-components.sh` (automatically removes from components.yaml) +3. **Validate**: Run `./validate-sync.sh` to confirm removal ## Scripts -**`generate-compare-components.sh`** - Syncs `components.yaml` with `root/values.yaml` -- Run after modifying apps in `root/values.yaml` -- Preserves existing metadata +### Generation Scripts +**`generate-compare-components.sh`** - Syncs `components.yaml` with enabled apps from `root/values.yaml` +- Processes only apps listed in `enabledApps` (excludes `-config` apps) +- Includes pre-validation to catch configuration issues early +- Preserves existing metadata (sourceUrl, projectUrl, license fields) +- Creates timestamped backups when needed **`update_licenses.sh`** - Auto-populates license info from GitHub - Run after updating URLs or to refresh licenses - Only works with GitHub project URLs +### Validation Scripts (New Modular System) +**`validate-sync.sh`** - 🛡️ **Main validation command** - Comprehensive SBOM sync validator +- Orchestrates all validation checks +- Use this for complete validation before commits + +**Individual Validators** (for targeted debugging): +- **`validate-enabled-apps.sh`** - Checks enabledApps have corresponding app definitions +- **`validate-components-sync.sh`** - Verifies components.yaml reflects current enabledApps +- **`validate-metadata.sh`** - Ensures all required metadata fields are populated + +## Validation Workflow + +The new modular validation system ensures data consistency: + +``` +1. EnabledApps Consistency Check + ├── Validates all enabledApps have app definitions + └── Filters out -config apps appropriately + +2. Components Sync Check + ├── Verifies components.yaml matches enabledApps + ├── Checks for missing/extra components + └── Validates path/valuesFile consistency + +3. Metadata Completeness Check + ├── Ensures sourceUrl and projectUrl are populated + └── Verifies license and licenseUrl fields exist +``` + ## Required Fields in components.yaml -- **sourceUrl**: Where to download the chart/manifest -- **projectUrl**: Main project repository (use GitHub for auto-license detection) +- **sourceUrl**: Where to download the chart/manifest (⚠️ Manual entry required) +- **projectUrl**: Main project repository (⚠️ Manual entry required - use GitHub for auto-license detection) - **license/licenseUrl**: Auto-populated from GitHub by `update_licenses.sh` +- **path**: Auto-synced from values.yaml by generation script +- **valuesFile**: Auto-synced from values.yaml when present + +## CI/CD Integration + +The GitHub workflow `.github/workflows/pr-component-validation.yaml` now includes: +1. **EnabledApps validation** (prevents mismatched configurations) +2. **Component generation** (ensures SBOM reflects enabled apps) +3. **Metadata validation** (ensures completeness) +4. **Sync verification** (catches uncommitted changes) + +## Important Notes + +- **EnabledApps is the source of truth**: Components are generated only for apps in the `enabledApps` list +- **Manual metadata required**: `sourceUrl` and `projectUrl` must be added manually (requires human knowledge) +- **Scripts are idempotent**: Safe to run multiple times +- **Validation before commit**: Always run `./validate-sync.sh` before creating PRs +- **Backup safety**: Existing data is preserved through timestamped backups + +## Troubleshooting + +**Error: "Enabled app has no definition"** +→ Add the app definition to the `apps` section in `root/values.yaml` + +**Error: "Component missing/extra"** +→ Run `./generate-compare-components.sh` to sync components.yaml + +**Error: "Missing sourceUrl/projectUrl"** +→ Manually add the missing URLs to components.yaml -## Notes -- Scripts are safe to run multiple times -- Verify auto-populated data before creating PRs +**Error: "Path/configuration mismatch"** +→ Run `./generate-compare-components.sh` to sync path information