project-standalo-sonic-cloud/skills/guardrail-orchestrator/scripts/validate_manifest.py

130 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Validate project manifest integrity."""
import argparse
import json
import os
import sys
def validate_structure(manifest: dict) -> list:
"""Validate manifest has required structure."""
errors = []
required_keys = ["project", "state", "entities", "dependencies"]
for key in required_keys:
if key not in manifest:
errors.append(f"Missing required key: {key}")
if "entities" in manifest:
entity_types = ["pages", "components", "api_endpoints", "database_tables"]
for etype in entity_types:
if etype not in manifest["entities"]:
errors.append(f"Missing entity type: {etype}")
return errors
def validate_pages(pages: list) -> list:
"""Validate page entities."""
errors = []
for page in pages:
if "id" not in page:
errors.append(f"Page missing id: {page}")
if "path" not in page:
errors.append(f"Page {page.get('id', 'unknown')} missing path")
if "file_path" not in page:
errors.append(f"Page {page.get('id', 'unknown')} missing file_path")
return errors
def validate_components(components: list) -> list:
"""Validate component entities."""
errors = []
for comp in components:
if "id" not in comp:
errors.append(f"Component missing id: {comp}")
if "name" not in comp:
errors.append(f"Component {comp.get('id', 'unknown')} missing name")
if "file_path" not in comp:
errors.append(f"Component {comp.get('id', 'unknown')} missing file_path")
return errors
def validate_apis(apis: list) -> list:
"""Validate API endpoint entities."""
errors = []
for api in apis:
if "id" not in api:
errors.append(f"API missing id: {api}")
if "method" not in api:
errors.append(f"API {api.get('id', 'unknown')} missing method")
if "path" not in api:
errors.append(f"API {api.get('id', 'unknown')} missing path")
return errors
def validate_tables(tables: list) -> list:
"""Validate database table entities."""
errors = []
for table in tables:
if "id" not in table:
errors.append(f"Table missing id: {table}")
if "name" not in table:
errors.append(f"Table {table.get('id', 'unknown')} missing name")
if "columns" not in table:
errors.append(f"Table {table.get('id', 'unknown')} missing columns")
return errors
def main():
parser = argparse.ArgumentParser(description="Validate project manifest")
parser.add_argument("--strict", action="store_true", help="Treat warnings as errors")
parser.add_argument("--manifest", default="project_manifest.json", help="Path to manifest")
args = parser.parse_args()
manifest_path = args.manifest
if not os.path.isabs(manifest_path):
manifest_path = os.path.join(os.getcwd(), manifest_path)
if not os.path.exists(manifest_path):
print(f"Error: Manifest not found at {manifest_path}")
return 1
with open(manifest_path) as f:
manifest = json.load(f)
errors = []
warnings = []
# Structure validation
errors.extend(validate_structure(manifest))
if "entities" in manifest:
errors.extend(validate_pages(manifest["entities"].get("pages", [])))
errors.extend(validate_components(manifest["entities"].get("components", [])))
errors.extend(validate_apis(manifest["entities"].get("api_endpoints", [])))
errors.extend(validate_tables(manifest["entities"].get("database_tables", [])))
# Report results
if errors:
print("VALIDATION FAILED")
for error in errors:
print(f" ERROR: {error}")
return 1
if warnings:
print("VALIDATION PASSED WITH WARNINGS")
for warning in warnings:
print(f" WARNING: {warning}")
if args.strict:
return 1
return 0
print("VALIDATION PASSED")
return 0
if __name__ == "__main__":
exit(main())