release orchestrator pivot, architecture and planning

This commit is contained in:
2026-01-10 22:37:22 +02:00
parent c84f421e2f
commit d509c44411
130 changed files with 70292 additions and 721 deletions

View 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
```