# Extension Registry Service\n\nA high-performance Rust microservice that provides a unified REST API for extension discovery, versioning,\nand download from multiple sources (Gitea releases and OCI registries).\n\n## Features\n\n- **Multi-Backend Support**: Fetch extensions from Gitea releases and OCI registries\n- **Unified REST API**: Single API for all extension operations\n- **Smart Caching**: LRU cache with TTL to reduce backend API calls\n- **Prometheus Metrics**: Built-in metrics for monitoring\n- **Health Monitoring**: Health checks for all backends\n- **Type-Safe**: Strong typing for extension metadata\n- **Async/Await**: High-performance async operations with Tokio\n- **Docker Support**: Production-ready containerization\n\n## Architecture\n\n```{$detected_lang}\n┌─────────────────────────────────────────────────\n────────────┐\n│                    Extension Registry API                   │\n│                         (axum)                              │\n├─────────────────────────────────────────────────\n────────────┤\n│                                                             │\n│  ┌────────────────┐  ┌────────────────┐  \n┌──────────────┐   │\n│  │  Gitea Client  │  │   OCI Client   │  │  LRU Cache   │   │\n│  │  (reqwest)     │  │   (reqwest)    │  │  (parking)   │   │\n│  └────────────────┘  └────────────────┘  \n└──────────────┘   │\n│         │                    │                    │         │\n└─────────┼────────────────────┼──────────────────\n──┼─────────┘\n          │                    │                    │\n          ▼                    ▼                    ▼\n    ┌──────────┐         ┌──────────┐        ┌──────────┐\n    │  Gitea   │         │   OCI    │        │  Memory  │\n    │ Releases │         │ Registry │        │          │\n    └──────────┘         └──────────┘        └──────────┘\n```\n\n## Installation\n\n### Building from Source\n\n```{$detected_lang}\ncd provisioning/platform/extension-registry\ncargo build --release\n```\n\n### Docker Build\n\n```{$detected_lang}\ndocker build -t extension-registry:latest .\n```\n\n### Running with Cargo\n\n```{$detected_lang}\ncargo run -- --config config.toml --port 8082\n```\n\n### Running with Docker\n\n```{$detected_lang}\ndocker run -d \\n  -p 8082:8082 \\n  -v $(pwd)/config.toml:/app/config.toml:ro \\n  -v $(pwd)/tokens:/app/tokens:ro \\n  extension-registry:latest\n```\n\n## Configuration\n\nCreate a `config.toml` file (see `config.example.toml`):\n\n```{$detected_lang}\n[server]\nhost = "0.0.0.0"\nport = 8082\nworkers = 4\nenable_cors = true\nenable_compression = true\n\n# Gitea backend (optional)\n[gitea]\nurl = "https://gitea.example.com"\norganization = "provisioning-extensions"\ntoken_path = "/path/to/gitea-token.txt"\ntimeout_seconds = 30\nverify_ssl = true\n\n# OCI registry backend (optional)\n[oci]\nregistry = "registry.example.com"\nnamespace = "provisioning"\nauth_token_path = "/path/to/oci-token.txt"\ntimeout_seconds = 30\nverify_ssl = true\n\n# Cache configuration\n[cache]\ncapacity = 1000\nttl_seconds = 300\nenable_metadata_cache = true\nenable_list_cache = true\n```\n\n**Note**: At least one backend (Gitea or OCI) must be configured.\n\n## API Endpoints\n\n### Extension Operations\n\n#### List Extensions\n\n```{$detected_lang}\nGET /api/v1/extensions\n```\n\nQuery parameters:\n\n- `type` (optional): Filter by extension type (`provider`, `taskserv`, `cluster`)\n- `source` (optional): Filter by source (`gitea`, `oci`)\n- `limit` (optional): Maximum results (default: 100)\n- `offset` (optional): Pagination offset (default: 0)\n\nExample:\n\n```{$detected_lang}\ncurl http://localhost:8082/api/v1/extensions?type=provider&limit=10\n```\n\nResponse:\n\n```{$detected_lang}\n[\n  {\n    "name": "aws",\n    "type": "provider",\n    "version": "1.2.0",\n    "description": "AWS provider for provisioning",\n    "author": "provisioning-team",\n    "repository": "https://gitea.example.com/org/aws_prov",\n    "source": "gitea",\n    "published_at": "2025-10-06T12:00:00Z",\n    "download_url": "https://gitea.example.com/org/aws_prov/releases/download/1.2.0/aws_prov.tar.gz",\n    "size": 1024000\n  }\n]\n```\n\n#### Get Extension\n\n```{$detected_lang}\nGET /api/v1/extensions/{type}/{name}\n```\n\nExample:\n\n```{$detected_lang}\ncurl http://localhost:8082/api/v1/extensions/provider/aws\n```\n\n#### List Versions\n\n```{$detected_lang}\nGET /api/v1/extensions/{type}/{name}/versions\n```\n\nExample:\n\n```{$detected_lang}\ncurl http://localhost:8082/api/v1/extensions/provider/aws/versions\n```\n\nResponse:\n\n```{$detected_lang}\n[\n  {\n    "version": "1.2.0",\n    "published_at": "2025-10-06T12:00:00Z",\n    "download_url": "https://gitea.example.com/org/aws_prov/releases/download/1.2.0/aws_prov.tar.gz",\n    "size": 1024000\n  },\n  {\n    "version": "1.1.0",\n    "published_at": "2025-09-15T10:30:00Z",\n    "download_url": "https://gitea.example.com/org/aws_prov/releases/download/1.1.0/aws_prov.tar.gz",\n    "size": 980000\n  }\n]\n```\n\n#### Download Extension\n\n```{$detected_lang}\nGET /api/v1/extensions/{type}/{name}/{version}\n```\n\nExample:\n\n```{$detected_lang}\ncurl -O http://localhost:8082/api/v1/extensions/provider/aws/1.2.0\n```\n\nReturns binary data with `Content-Type: application/octet-stream`.\n\n#### Search Extensions\n\n```{$detected_lang}\nGET /api/v1/extensions/search?q={query}\n```\n\nQuery parameters:\n\n- `q` (required): Search query\n- `type` (optional): Filter by extension type\n- `limit` (optional): Maximum results (default: 50)\n\nExample:\n\n```{$detected_lang}\ncurl http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv\n```\n\n### System Endpoints\n\n#### Health Check\n\n```{$detected_lang}\nGET /api/v1/health\n```\n\nExample:\n\n```{$detected_lang}\ncurl http://localhost:8082/api/v1/health\n```\n\nResponse:\n\n```{$detected_lang}\n{\n  "status": "healthy",\n  "version": "0.1.0",\n  "uptime": 3600,\n  "backends": {\n    "gitea": {\n      "enabled": true,\n      "healthy": true\n    },\n    "oci": {\n      "enabled": true,\n      "healthy": true\n    }\n  }\n}\n```\n\n#### Metrics\n\n```{$detected_lang}\nGET /api/v1/metrics\n```\n\nReturns Prometheus-formatted metrics:\n\n```{$detected_lang}\n# HELP http_requests_total Total HTTP requests\n# TYPE http_requests_total counter\nhttp_requests_total 1234\n\n# HELP cache_hits_total Total cache hits\n# TYPE cache_hits_total counter\ncache_hits_total 567\n\n# HELP cache_misses_total Total cache misses\n# TYPE cache_misses_total counter\ncache_misses_total 123\n```\n\n#### Cache Statistics\n\n```{$detected_lang}\nGET /api/v1/cache/stats\n```\n\nResponse:\n\n```{$detected_lang}\n{\n  "list_entries": 45,\n  "metadata_entries": 120,\n  "version_entries": 80,\n  "total_entries": 245\n}\n```\n\n## Extension Naming Conventions\n\n### Gitea Repositories\n\nExtensions in Gitea follow specific naming patterns:\n\n- **Providers**: `{name}_prov` (e.g., `aws_prov`, `upcloud_prov`)\n- **Task Services**: `{name}_taskserv` (e.g., `kubernetes_taskserv`, `postgres_taskserv`)\n- **Clusters**: `{name}_cluster` (e.g., `buildkit_cluster`, `ci_cluster`)\n\n### OCI Artifacts\n\nExtensions in OCI registries follow these patterns:\n\n- **Providers**: `{namespace}/{name}-provider` (e.g., `provisioning/aws-provider`)\n- **Task Services**: `{namespace}/{name}-taskserv` (e.g., `provisioning/kubernetes-taskserv`)\n- **Clusters**: `{namespace}/{name}-cluster` (e.g., `provisioning/buildkit-cluster`)\n\n## Caching Strategy\n\nThe service implements a multi-level LRU cache with TTL:\n\n1. **List Cache**: Caches extension lists (filtered by type/source)\n2. **Metadata Cache**: Caches individual extension metadata\n3. **Version Cache**: Caches version lists per extension\n\nCache behavior:\n\n- **Capacity**: Configurable (default: 1000 entries)\n- **TTL**: Configurable (default: 5 minutes)\n- **Eviction**: LRU (Least Recently Used)\n- **Invalidation**: Automatic on TTL expiration\n\nCache keys:\n\n- List: `list:{type}:{source}`\n- Metadata: `{type}/{name}`\n- Versions: `{type}/{name}/versions`\n\n## Error Handling\n\nThe API uses standard HTTP status codes:\n\n- `200 OK`: Successful operation\n- `400 Bad Request`: Invalid input (e.g., invalid extension type)\n- `401 Unauthorized`: Authentication failed\n- `404 Not Found`: Extension not found\n- `429 Too Many Requests`: Rate limit exceeded\n- `500 Internal Server Error`: Server error\n\nError response format:\n\n```{$detected_lang}\n{\n  "error": "not_found",\n  "message": "Extension provider/nonexistent not found"\n}\n```\n\n## Metrics and Monitoring\n\n### Prometheus Metrics\n\nAvailable metrics:\n\n- `http_requests_total`: Total HTTP requests\n- `http_request_duration_seconds`: Request duration histogram\n- `cache_hits_total`: Total cache hits\n- `cache_misses_total`: Total cache misses\n- `extensions_total`: Total extensions served\n\n### Health Checks\n\nThe health endpoint checks:\n\n- Service uptime\n- Gitea backend connectivity\n- OCI backend connectivity\n- Overall service status\n\n## Development\n\n### Project Structure\n\n```{$detected_lang}\nextension-registry/\n├── Cargo.toml              # Rust dependencies\n├── src/\n│   ├── main.rs             # Entry point\n│   ├── lib.rs              # Library exports\n│   ├── config.rs           # Configuration management\n│   ├── error.rs            # Error types\n│   ├── api/\n│   │   ├── handlers.rs     # HTTP handlers\n│   │   └── routes.rs       # Route definitions\n│   ├── gitea/\n│   │   ├── client.rs       # Gitea API client\n│   │   └── models.rs       # Gitea data models\n│   ├── oci/\n│   │   ├── client.rs       # OCI registry client\n│   │   └── models.rs       # OCI data models\n│   ├── cache/\n│   │   └── lru_cache.rs    # LRU caching\n│   └── models/\n│       └── extension.rs    # Extension models\n├── tests/\n│   └── integration_test.rs # Integration tests\n├── Dockerfile              # Docker build\n└── README.md               # This file\n```\n\n### Running Tests\n\n```{$detected_lang}\n# Run all tests\ncargo test\n\n# Run with output\ncargo test -- --nocapture\n\n# Run specific test\ncargo test test_health_check\n```\n\n### Code Quality\n\n```{$detected_lang}\n# Format code\ncargo fmt\n\n# Run clippy\ncargo clippy\n\n# Check for security vulnerabilities\ncargo audit\n```\n\n## Deployment\n\n### Systemd Service\n\nCreate `/etc/systemd/system/extension-registry.service`:\n\n```{$detected_lang}\n[Unit]\nDescription=Extension Registry Service\nAfter=network.target\n\n[Service]\nType=simple\nUser=registry\nWorkingDirectory=/opt/extension-registry\nExecStart=/usr/local/bin/extension-registry --config /etc/extension-registry/config.toml\nRestart=on-failure\nRestartSec=5s\n\n[Install]\nWantedBy=multi-user.target\n```\n\nEnable and start:\n\n```{$detected_lang}\nsudo systemctl enable extension-registry\nsudo systemctl start extension-registry\nsudo systemctl status extension-registry\n```\n\n### Docker Compose\n\n```{$detected_lang}\nversion: '3.8'\n\nservices:\n  extension-registry:\n    image: extension-registry:latest\n    ports:\n      - "8082:8082"\n    volumes:\n      - ./config.toml:/app/config.toml:ro\n      - ./tokens:/app/tokens:ro\n    restart: unless-stopped\n    healthcheck:\n      test: ["CMD", "curl", "-f", "http://localhost:8082/api/v1/health"]\n      interval: 30s\n      timeout: 3s\n      retries: 3\n      start_period: 5s\n```\n\n### Kubernetes Deployment\n\n```{$detected_lang}\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: extension-registry\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: extension-registry\n  template:\n    metadata:\n      labels:\n        app: extension-registry\n    spec:\n      containers:\n      - name: extension-registry\n        image: extension-registry:latest\n        ports:\n        - containerPort: 8082\n        volumeMounts:\n        - name: config\n          mountPath: /app/config.toml\n          subPath: config.toml\n        - name: tokens\n          mountPath: /app/tokens\n        livenessProbe:\n          httpGet:\n            path: /api/v1/health\n            port: 8082\n          initialDelaySeconds: 5\n          periodSeconds: 10\n        readinessProbe:\n          httpGet:\n            path: /api/v1/health\n            port: 8082\n          initialDelaySeconds: 5\n          periodSeconds: 5\n      volumes:\n      - name: config\n        configMap:\n          name: extension-registry-config\n      - name: tokens\n        secret:\n          secretName: extension-registry-tokens\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: extension-registry\nspec:\n  selector:\n    app: extension-registry\n  ports:\n  - port: 8082\n    targetPort: 8082\n  type: ClusterIP\n```\n\n## Security\n\n### Authentication\n\n- Gitea: Token-based authentication via `token_path`\n- OCI: Optional token authentication via `auth_token_path`\n\n### Best Practices\n\n1. **Store tokens securely**: Use file permissions (600) for token files\n2. **Enable SSL verification**: Set `verify_ssl = true` in production\n3. **Use HTTPS**: Always use HTTPS for Gitea and OCI registries\n4. **Limit CORS**: Configure CORS appropriately for production\n5. **Rate limiting**: Consider adding rate limiting for public APIs\n6. **Network isolation**: Run service in isolated network segments\n\n## Performance\n\n### Benchmarks\n\nTypical performance characteristics:\n\n- **Cached requests**: <5ms response time\n- **Uncached requests**: 50-200ms (depends on backend latency)\n- **Cache hit ratio**: ~85-95% in typical workloads\n- **Throughput**: 1000+ req/s on modern hardware\n\n### Optimization Tips\n\n1. **Increase cache capacity**: For large extension catalogs\n2. **Tune TTL**: Balance freshness vs. performance\n3. **Use multiple workers**: Scale with CPU cores\n4. **Enable compression**: Reduce bandwidth usage\n5. **Connection pooling**: Reuse HTTP connections to backends\n\n## Troubleshooting\n\n### Common Issues\n\n#### Service won't start\n\n- Check configuration file syntax\n- Verify token files exist and are readable\n- Check network connectivity to backends\n\n#### Extensions not found\n\n- Verify backend configuration (URL, organization, namespace)\n- Check backend connectivity with health endpoint\n- Review logs for authentication errors\n\n#### Slow responses\n\n- Check backend latency\n- Increase cache capacity or TTL\n- Review Prometheus metrics for bottlenecks\n\n### Logging\n\nEnable debug logging:\n\n```{$detected_lang}\nextension-registry --log-level debug\n```\n\nEnable JSON logging for structured logs:\n\n```{$detected_lang}\nextension-registry --json-log\n```\n\n## License\n\nPart of the Provisioning Project.\n\n## Contributing\n\nSee main project documentation for contribution guidelines.\n\n## Support\n\nFor issues and questions, please refer to the main provisioning project documentation.