# INTHUB: Integration Hub **Purpose**: Central management of all external integrations (SCM, CI, registries, vaults, targets). ## Modules ### Module: `integration-manager` | Aspect | Specification | |--------|---------------| | **Responsibility** | CRUD for integration instances; plugin type registry | | **Dependencies** | `plugin-registry`, `authority` (for credentials) | | **Data Entities** | `Integration`, `IntegrationType`, `IntegrationCredential` | | **Events Produced** | `integration.created`, `integration.updated`, `integration.deleted`, `integration.health_changed` | | **Events Consumed** | `plugin.registered`, `plugin.unregistered` | **Key Operations**: ``` CreateIntegration(type, name, config, credentials) → Integration UpdateIntegration(id, config, credentials) → Integration DeleteIntegration(id) → void TestConnection(id) → ConnectionTestResult DiscoverResources(id, resourceType) → Resource[] GetIntegrationHealth(id) → HealthStatus ListIntegrations(filter) → Integration[] ``` **Integration Entity**: ```typescript interface Integration { id: UUID; tenantId: UUID; type: string; // "scm.github", "registry.harbor" name: string; // user-defined name config: IntegrationConfig; // type-specific config credentialId: UUID; // reference to vault healthStatus: HealthStatus; lastHealthCheck: DateTime; createdAt: DateTime; updatedAt: DateTime; } interface IntegrationConfig { endpoint: string; authMode: "token" | "oauth" | "mtls" | "iam"; timeout: number; retryPolicy: RetryPolicy; customHeaders?: Record; // Type-specific fields added by plugin [key: string]: any; } ``` --- ### Module: `connection-profiles` | Aspect | Specification | |--------|---------------| | **Responsibility** | Default settings management; "last used" pattern | | **Dependencies** | `integration-manager` | | **Data Entities** | `ConnectionProfile`, `ProfileTemplate` | **Behavior**: When user adds a new integration instance: 1. Wizard defaults to last used endpoint, auth mode, network settings 2. Secrets are **never** auto-reused (explicit confirmation required) 3. User can save as named profile for reuse **Profile Entity**: ```typescript interface ConnectionProfile { id: UUID; tenantId: UUID; name: string; // "Production GitHub" integrationType: string; defaultConfig: Partial; isDefault: boolean; lastUsedAt: DateTime; createdBy: UUID; } ``` --- ### Module: `connector-runtime` | Aspect | Specification | |--------|---------------| | **Responsibility** | Execute plugin connector logic in controlled environment | | **Dependencies** | `plugin-loader`, `plugin-sandbox` | | **Protocol** | gRPC (preferred) or HTTP/REST | **Connector Interface** (implemented by plugins): ```protobuf service Connector { // Connection management rpc TestConnection(TestConnectionRequest) returns (TestConnectionResponse); rpc GetHealth(HealthRequest) returns (HealthResponse); // Resource discovery rpc DiscoverResources(DiscoverRequest) returns (DiscoverResponse); rpc ListRepositories(ListReposRequest) returns (ListReposResponse); rpc ListBranches(ListBranchesRequest) returns (ListBranchesResponse); rpc ListTags(ListTagsRequest) returns (ListTagsResponse); // Registry operations rpc ResolveTagToDigest(ResolveRequest) returns (ResolveResponse); rpc FetchManifest(ManifestRequest) returns (ManifestResponse); rpc VerifyDigest(VerifyRequest) returns (VerifyResponse); // Secrets operations rpc GetSecretsRef(SecretsRequest) returns (SecretsResponse); rpc FetchSecret(FetchSecretRequest) returns (FetchSecretResponse); // Workflow step execution rpc ExecuteStep(StepRequest) returns (stream StepResponse); rpc CancelStep(CancelRequest) returns (CancelResponse); } ``` **Request/Response Types**: ```protobuf message TestConnectionRequest { string integration_id = 1; map config = 2; string credential_ref = 3; } message TestConnectionResponse { bool success = 1; string error_message = 2; map details = 3; int64 latency_ms = 4; } message ResolveRequest { string integration_id = 1; string image_ref = 2; // "myapp:v2.3.1" } message ResolveResponse { string digest = 1; // "sha256:abc123..." string manifest_type = 2; int64 size_bytes = 3; google.protobuf.Timestamp pushed_at = 4; } ``` --- ### Module: `doctor-checks` | Aspect | Specification | |--------|---------------| | **Responsibility** | Integration health diagnostics; troubleshooting | | **Dependencies** | `integration-manager`, `connector-runtime` | **Doctor Check Types**: | Check | Purpose | Pass Criteria | |-------|---------|---------------| | **Connectivity** | Can reach endpoint | TCP connect succeeds | | **TLS** | Certificate valid | Chain validates, not expired | | **Authentication** | Credentials valid | Auth request succeeds | | **Authorization** | Permissions sufficient | Required scopes present | | **Version** | API version supported | Version in supported range | | **Rate Limit** | Quota available | >10% remaining | | **Latency** | Response time acceptable | <5s p99 | **Doctor Check Output**: ```typescript interface DoctorCheckResult { checkType: string; status: "pass" | "warn" | "fail"; message: string; details: Record; suggestions: string[]; runAt: DateTime; durationMs: number; } interface DoctorReport { integrationId: UUID; overallStatus: "healthy" | "degraded" | "unhealthy"; checks: DoctorCheckResult[]; generatedAt: DateTime; } ``` --- ## Cache Eviction Policies Integration health status and connector results are cached to reduce load on external systems. **All caches MUST have bounded size and TTL-based eviction**: | Cache Type | Purpose | TTL | Max Size | Eviction Strategy | |-----------|---------|-----|----------|-------------------| | **Health Checks** | Integration health status | 5 minutes | 1,000 entries | Sliding expiration | | **Connection Tests** | Test connection results | 2 minutes | 500 entries | Sliding expiration | | **Resource Discovery** | Discovered resources (repos, tags) | 10 minutes | 5,000 entries | Sliding expiration | | **Tag Resolution** | Tag → digest mappings | 1 hour | 10,000 entries | Absolute expiration | **Implementation**: ```csharp public class IntegrationHealthCache { private readonly MemoryCache _cache; public IntegrationHealthCache() { _cache = new MemoryCache(new MemoryCacheOptions { SizeLimit = 1_000 // Max 1,000 integration health entries }); } public void CacheHealthStatus(Guid integrationId, HealthStatus status) { _cache.Set(integrationId, status, new MemoryCacheEntryOptions { Size = 1, SlidingExpiration = TimeSpan.FromMinutes(5) // 5-minute TTL }); } public HealthStatus? GetCachedHealthStatus(Guid integrationId) => _cache.Get(integrationId); } ``` **Reference**: See [Implementation Guide](../implementation-guide.md#caching) for cache implementation patterns. --- ## Integration Types The following integration types are supported (via plugins): ### SCM Integrations | Type | Plugin | Capabilities | |------|--------|--------------| | `scm.github` | Built-in | repos, branches, commits, webhooks, status | | `scm.gitlab` | Built-in | repos, branches, commits, webhooks, pipelines | | `scm.bitbucket` | Plugin | repos, branches, commits, webhooks | | `scm.azure_repos` | Plugin | repos, branches, commits, pipelines | ### Registry Integrations | Type | Plugin | Capabilities | |------|--------|--------------| | `registry.harbor` | Built-in | repos, tags, digests, scanning status | | `registry.ecr` | Plugin | repos, tags, digests, IAM auth | | `registry.gcr` | Plugin | repos, tags, digests | | `registry.dockerhub` | Plugin | repos, tags, digests | | `registry.ghcr` | Plugin | repos, tags, digests | | `registry.acr` | Plugin | repos, tags, digests | ### Vault Integrations | Type | Plugin | Capabilities | |------|--------|--------------| | `vault.hashicorp` | Built-in | KV, transit, PKI | | `vault.aws_secrets` | Plugin | secrets, IAM auth | | `vault.azure_keyvault` | Plugin | secrets, certificates | | `vault.gcp_secrets` | Plugin | secrets, IAM auth | ### CI Integrations | Type | Plugin | Capabilities | |------|--------|--------------| | `ci.github_actions` | Built-in | workflows, runs, artifacts, status | | `ci.gitlab_ci` | Built-in | pipelines, jobs, artifacts | | `ci.jenkins` | Plugin | jobs, builds, artifacts | | `ci.azure_pipelines` | Plugin | pipelines, runs, artifacts | ### Router Integrations (for Progressive Delivery) | Type | Plugin | Capabilities | |------|--------|--------------| | `router.nginx` | Plugin | upstream config, reload | | `router.haproxy` | Plugin | backend config, reload | | `router.traefik` | Plugin | dynamic config | | `router.aws_alb` | Plugin | target groups, listener rules | --- ## Database Schema ```sql -- Integration types (populated by plugins) CREATE TABLE release.integration_types ( id TEXT PRIMARY KEY, -- "scm.github" plugin_id UUID REFERENCES release.plugins(id), display_name TEXT NOT NULL, description TEXT, icon_url TEXT, config_schema JSONB NOT NULL, -- JSON Schema for config capabilities TEXT[] NOT NULL, -- ["repos", "webhooks", "status"] created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- Integration instances CREATE TABLE release.integrations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id), type_id TEXT NOT NULL REFERENCES release.integration_types(id), name TEXT NOT NULL, config JSONB NOT NULL, credential_ref TEXT NOT NULL, -- vault reference health_status TEXT NOT NULL DEFAULT 'unknown', last_health_check TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), created_by UUID NOT NULL REFERENCES users(id), UNIQUE(tenant_id, name) ); -- Connection profiles CREATE TABLE release.connection_profiles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id), name TEXT NOT NULL, integration_type TEXT NOT NULL, default_config JSONB NOT NULL, is_default BOOLEAN NOT NULL DEFAULT false, last_used_at TIMESTAMPTZ, created_by UUID NOT NULL REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE(tenant_id, name) ); -- Doctor check history CREATE TABLE release.doctor_checks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), integration_id UUID NOT NULL REFERENCES release.integrations(id), check_type TEXT NOT NULL, status TEXT NOT NULL, message TEXT, details JSONB, duration_ms INTEGER NOT NULL, run_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX idx_doctor_checks_integration ON release.doctor_checks(integration_id, run_at DESC); ``` --- ## API Endpoints See [API Documentation](../api/overview.md) for full specification. ``` GET /api/v1/integration-types # List available types GET /api/v1/integration-types/{type} # Get type details GET /api/v1/integrations # List integrations POST /api/v1/integrations # Create integration GET /api/v1/integrations/{id} # Get integration PUT /api/v1/integrations/{id} # Update integration DELETE /api/v1/integrations/{id} # Delete integration POST /api/v1/integrations/{id}/test # Test connection GET /api/v1/integrations/{id}/health # Get health status POST /api/v1/integrations/{id}/doctor # Run doctor checks GET /api/v1/integrations/{id}/resources # Discover resources GET /api/v1/connection-profiles # List profiles POST /api/v1/connection-profiles # Create profile GET /api/v1/connection-profiles/{id} # Get profile PUT /api/v1/connection-profiles/{id} # Update profile DELETE /api/v1/connection-profiles/{id} # Delete profile ```