release orchestrator pivot, architecture and planning
This commit is contained in:
373
docs/modules/release-orchestrator/modules/integration-hub.md
Normal file
373
docs/modules/release-orchestrator/modules/integration-hub.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# 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<string, string>;
|
||||
// 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<IntegrationConfig>;
|
||||
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<string, string> config = 2;
|
||||
string credential_ref = 3;
|
||||
}
|
||||
|
||||
message TestConnectionResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
map<string, string> 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<string, any>;
|
||||
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<HealthStatus>(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
|
||||
```
|
||||
Reference in New Issue
Block a user