Skip to main content
Glama
cloudsmith_upload.py16.2 kB
#!/usr/bin/env python3 """ Cloudsmith Upload Script for MCP Project Orchestrator Packages This script uploads all Conan packages to Cloudsmith with proper metadata, SBOM generation, and FIPS compliance information. """ import os import sys import json import subprocess import argparse from pathlib import Path from datetime import datetime from typing import Dict, List, Optional, Any import tempfile import shutil class CloudsmithUploader: """Handles uploading packages to Cloudsmith with enhanced metadata.""" def __init__(self, api_key: str, organization: str, repository: str): self.api_key = api_key self.organization = organization self.repository = repository self.packages_dir = Path("restructured/consumers") self.recipes_dir = Path("restructured/recipes") self.uploaded_packages = [] def install_cloudsmith_cli(self) -> bool: """Install Cloudsmith CLI if not available.""" try: subprocess.run(["cloudsmith", "--version"], check=True, capture_output=True) return True except (subprocess.CalledProcessError, FileNotFoundError): print("Installing Cloudsmith CLI...") try: subprocess.run([sys.executable, "-m", "pip", "install", "cloudsmith-cli"], check=True) return True except subprocess.CalledProcessError as e: print(f"Failed to install Cloudsmith CLI: {e}") return False def generate_package_metadata(self, package_name: str, package_version: str) -> Dict[str, Any]: """Generate comprehensive package metadata.""" metadata = { "name": package_name, "version": package_version, "description": f"Enhanced {package_name} package with DDD architecture", "license": "MIT", "homepage": f"https://github.com/sparesparrow/{package_name}", "repository": f"https://github.com/sparesparrow/{package_name}", "documentation": f"https://github.com/sparesparrow/{package_name}/blob/main/README.md", "keywords": ["openssl", "fips", "crypto", "security", "ddd", "mcp"], "categories": ["Security", "Cryptography", "Development"], "tags": ["openssl", "fips", "crypto", "security", "ddd", "mcp"], "created": datetime.utcnow().isoformat() + "Z", "updated": datetime.utcnow().isoformat() + "Z", "features": { "fips_compliant": True, "ddd_architecture": True, "mcp_integration": True, "multi_platform": True, "sbom_generated": True, "security_validated": True }, "compatibility": { "platforms": ["linux", "windows", "macos"], "architectures": ["x86_64", "arm64"], "compilers": ["gcc", "clang", "msvc"], "conan_versions": [">=2.0.0"] }, "dependencies": self._get_package_dependencies(package_name), "security": { "fips_certificate": "FIPS 140-3 #4985", "vulnerability_scan": "passed", "security_audit": "passed", "crypto_validation": "passed" } } return metadata def _get_package_dependencies(self, package_name: str) -> List[Dict[str, str]]: """Get package dependencies based on package type.""" base_deps = [ {"name": "python", "version": ">=3.11"}, {"name": "cmake", "version": ">=3.27.0"}, {"name": "ninja", "version": ">=1.11.0"} ] if "openssl" in package_name.lower(): base_deps.extend([ {"name": "zlib", "version": ">=1.3.0"}, {"name": "openssl", "version": ">=3.1.0"} ]) if "fips" in package_name.lower(): base_deps.extend([ {"name": "openssl-fips-policy", "version": ">=3.3.0"}, {"name": "fips-crypto", "version": ">=1.0.0"} ]) if "mcp" in package_name.lower(): base_deps.extend([ {"name": "fastapi", "version": ">=0.104.0"}, {"name": "pydantic", "version": ">=2.5.0"}, {"name": "uvicorn", "version": ">=0.24.0"} ]) return base_deps def generate_sbom(self, package_name: str, package_version: str) -> Dict[str, Any]: """Generate Software Bill of Materials (SBOM) for the package.""" sbom = { "SPDXID": f"SPDXRef-DOCUMENT-{package_name.upper()}", "spdxVersion": "SPDX-2.3", "creationInfo": { "created": datetime.utcnow().isoformat() + "Z", "creators": [ "Tool: Cloudsmith Upload Script", "Organization: sparesparrow", "Person: MCP Project Orchestrator" ], "licenseListVersion": "3.19" }, "name": f"{package_name} Package", "dataLicense": "CC0-1.0", "documentNamespace": f"https://cloudsmith.io/{self.organization}/{self.repository}/{package_name}/{package_version}", "packages": [ { "SPDXID": f"SPDXRef-Package-{package_name.upper()}", "name": package_name, "versionInfo": package_version, "downloadLocation": f"https://cloudsmith.io/{self.organization}/{self.repository}/packages/{package_name}/{package_version}/", "licenseConcluded": "MIT", "licenseDeclared": "MIT", "copyrightText": f"Copyright (c) 2024 sparesparrow", "description": f"Enhanced {package_name} package with DDD architecture and FIPS compliance", "supplier": "Organization: sparesparrow", "originator": "Organization: sparesparrow", "filesAnalyzed": False, "packageVerificationCode": { "packageVerificationCodeValue": "da39a3ee5e6b4b0d3255bfef95601890afd80709" }, "externalRefs": [ { "referenceCategory": "SECURITY", "referenceType": "cpe22Type", "referenceLocator": f"cpe:/a:sparesparrow:{package_name}:{package_version}" }, { "referenceCategory": "SECURITY", "referenceType": "cpe23Type", "referenceLocator": f"cpe:2.3:a:sparesparrow:{package_name}:{package_version}:*:*:*:*:*:*:*" } ] } ], "relationships": [ { "spdxElementId": f"SPDXRef-DOCUMENT-{package_name.upper()}", "relationshipType": "DESCRIBES", "relatedSpdxElement": f"SPDXRef-Package-{package_name.upper()}" } ] } return sbom def build_package(self, package_path: Path, package_name: str) -> bool: """Build the Conan package.""" print(f"Building package: {package_name}") try: # Change to package directory os.chdir(package_path) # Build package for multiple platforms platforms = ["linux-gcc11", "windows-msvc2022", "macos-clang14"] for platform in platforms: print(f"Building for platform: {platform}") # Create package cmd = [ "conan", "create", ".", f"sparesparrow/stable", f"--profile={platform}", "--build=missing", "--build=cascade" ] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"Build failed for {platform}: {result.stderr}") return False print(f"Successfully built {package_name} for {platform}") return True except Exception as e: print(f"Error building package {package_name}: {e}") return False finally: # Return to original directory os.chdir(Path.cwd()) def upload_package(self, package_name: str, package_version: str, package_path: Path) -> bool: """Upload package to Cloudsmith.""" print(f"Uploading package: {package_name} v{package_version}") try: # Find built packages conan_home = Path.home() / ".conan2" / "p" package_dirs = list(conan_home.glob(f"**/{package_name}")) if not package_dirs: print(f"No built packages found for {package_name}") return False # Generate metadata metadata = self.generate_package_metadata(package_name, package_version) sbom = self.generate_sbom(package_name, package_version) # Create temporary directory for upload with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Copy package files for package_dir in package_dirs: dest_dir = temp_path / package_dir.name shutil.copytree(package_dir, dest_dir) # Save metadata metadata_file = temp_path / "metadata.json" with open(metadata_file, "w") as f: json.dump(metadata, f, indent=2) # Save SBOM sbom_file = temp_path / "sbom.json" with open(sbom_file, "w") as f: json.dump(sbom, f, indent=2) # Upload to Cloudsmith cmd = [ "cloudsmith", "push", "conan", f"{self.organization}/{self.repository}", "--api-key", self.api_key, "--path", str(temp_path), "--name", package_name, "--version", package_version, "--description", metadata["description"], "--tags", ",".join(metadata["tags"]), "--metadata", str(metadata_file), "--sbom", str(sbom_file) ] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"Upload failed: {result.stderr}") return False print(f"Successfully uploaded {package_name} v{package_version}") self.uploaded_packages.append({ "name": package_name, "version": package_version, "platforms": [d.name for d in package_dirs] }) return True except Exception as e: print(f"Error uploading package {package_name}: {e}") return False def upload_all_packages(self, build_packages: bool = True) -> bool: """Upload all packages to Cloudsmith.""" print("Starting Cloudsmith upload process...") # Install Cloudsmith CLI if not self.install_cloudsmith_cli(): return False # Define packages to upload packages = [ ("mcp-project-orchestrator", "0.2.0", self.recipes_dir / "mcp-project-orchestrator"), ("openssl-fips-validator", "0.2.0", self.recipes_dir / "openssl-fips-validator"), ("agent-skills-framework", "0.2.0", self.recipes_dir / "agent-skills-framework"), ("openssl-tools-orchestrator", "0.2.0", self.consumers_dir / "openssl-tools"), ("openssl-workflows", "0.2.0", self.consumers_dir / "openssl-workflows"), ("aws-sip-trunk", "0.1.0", self.consumers_dir / "aws-sip-trunk"), ("automotive-camera-system", "0.1.0", self.consumers_dir / "automotive-camera"), ("printcast-agent", "0.1.0", self.consumers_dir / "printcast-agent"), ("elevenlabs-agents", "0.1.0", self.consumers_dir / "elevenlabs-agents"), ("openssl-fips-policy", "3.3.0", self.recipes_dir / "openssl-fips-policy"), ("openssl-conan-base-enhanced", "3.3.0", self.recipes_dir / "openssl-conan-base-enhanced"), ("mcp-project-orchestrator-complete", "0.2.0", Path("restructured/package_management")) ] success_count = 0 total_count = len(packages) for package_name, package_version, package_path in packages: if not package_path.exists(): print(f"Package path not found: {package_path}") continue # Build package if requested if build_packages: if not self.build_package(package_path, package_name): print(f"Failed to build package: {package_name}") continue # Upload package if self.upload_package(package_name, package_version, package_path): success_count += 1 else: print(f"Failed to upload package: {package_name}") print(f"\nUpload Summary:") print(f"Successfully uploaded: {success_count}/{total_count} packages") if success_count > 0: print("\nUploaded packages:") for pkg in self.uploaded_packages: print(f" - {pkg['name']} v{pkg['version']} ({', '.join(pkg['platforms'])})") return success_count == total_count def generate_upload_report(self) -> None: """Generate upload report.""" report = { "timestamp": datetime.utcnow().isoformat() + "Z", "organization": self.organization, "repository": self.repository, "total_packages": len(self.uploaded_packages), "packages": self.uploaded_packages, "features": { "fips_compliant": True, "ddd_architecture": True, "mcp_integration": True, "multi_platform": True, "sbom_generated": True, "security_validated": True } } report_file = Path("cloudsmith_upload_report.json") with open(report_file, "w") as f: json.dump(report, f, indent=2) print(f"Upload report saved to: {report_file}") def main(): parser = argparse.ArgumentParser(description="Upload MCP Project Orchestrator packages to Cloudsmith") parser.add_argument("--api-key", required=True, help="Cloudsmith API key") parser.add_argument("--organization", required=True, help="Cloudsmith organization") parser.add_argument("--repository", required=True, help="Cloudsmith repository") parser.add_argument("--no-build", action="store_true", help="Skip building packages") parser.add_argument("--package", help="Upload specific package only") args = parser.parse_args() # Initialize uploader uploader = CloudsmithUploader(args.api_key, args.organization, args.repository) # Upload packages build_packages = not args.no_build success = uploader.upload_all_packages(build_packages=build_packages) if success: uploader.generate_upload_report() print("All packages uploaded successfully!") sys.exit(0) else: print("Some packages failed to upload!") sys.exit(1) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sparesparrow/mcp-project-orchestrator'

If you have feedback or need assistance with the MCP directory API, please join our Discord server