release orchestrator pivot, architecture and planning
This commit is contained in:
221
docs/modules/release-orchestrator/design/principles.md
Normal file
221
docs/modules/release-orchestrator/design/principles.md
Normal file
@@ -0,0 +1,221 @@
|
||||
# Design Principles & Invariants
|
||||
|
||||
> These principles are **inviolable** and MUST be reflected in all code, UI, documentation, and audit artifacts.
|
||||
|
||||
## Core Principles
|
||||
|
||||
### Principle 1: Release Identity via Digest
|
||||
|
||||
```
|
||||
INVARIANT: A release is a set of OCI image digests (component → digest mapping), never tags.
|
||||
```
|
||||
|
||||
- Tags are convenience inputs for resolution
|
||||
- Tags are resolved to digests at release creation time
|
||||
- All downstream operations (promotion, deployment, rollback) use digests
|
||||
- Digest mismatch at pull time = deployment failure (tamper detection)
|
||||
|
||||
**Implementation Requirements:**
|
||||
- Release creation API accepts tags but immediately resolves to digests
|
||||
- All internal references use `sha256:` prefixed digests
|
||||
- Agent deployment verifies digest at pull time
|
||||
- Rollback targets specific digest, not "previous tag"
|
||||
|
||||
### Principle 2: Determinism and Evidence
|
||||
|
||||
```
|
||||
INVARIANT: Every deployment/promotion produces an immutable evidence record.
|
||||
```
|
||||
|
||||
Evidence record contains:
|
||||
- **Who**: User identity (from Authority)
|
||||
- **What**: Release bundle (digests), target environment, target hosts
|
||||
- **Why**: Policy evaluation result, approval records, decision reasons
|
||||
- **How**: Generated artifacts (compose files, scripts), execution logs
|
||||
- **When**: Timestamps for request, decision, execution, completion
|
||||
|
||||
Evidence enables:
|
||||
- Audit-grade compliance reporting
|
||||
- Deterministic replay (same inputs + policy → same decision)
|
||||
- "Why blocked?" explainability
|
||||
|
||||
**Implementation Requirements:**
|
||||
- Evidence is generated synchronously with decision
|
||||
- Evidence is signed before storage
|
||||
- Evidence table is append-only (no UPDATE/DELETE)
|
||||
- Evidence includes hash of all inputs for replay verification
|
||||
|
||||
### Principle 3: Pluggable Everything, Stable Core
|
||||
|
||||
```
|
||||
INVARIANT: Integrations are plugins; the core orchestration engine is stable.
|
||||
```
|
||||
|
||||
**Plugins contribute:**
|
||||
- Configuration screens (UI)
|
||||
- Connector logic (runtime)
|
||||
- Step node types (workflow)
|
||||
- Doctor checks (diagnostics)
|
||||
- Agent types (deployment)
|
||||
|
||||
**Core engine provides:**
|
||||
- Workflow execution (DAG processing)
|
||||
- State machine management
|
||||
- Evidence generation
|
||||
- Policy evaluation
|
||||
- Credential brokering
|
||||
|
||||
**Implementation Requirements:**
|
||||
- Core has no hard-coded integrations
|
||||
- Plugin interface is versioned and stable
|
||||
- Plugin failures cannot crash core
|
||||
- Core provides fallback behavior when plugins unavailable
|
||||
|
||||
### Principle 4: No Feature Gating
|
||||
|
||||
```
|
||||
INVARIANT: All plans include all features. Limits are only:
|
||||
- Number of environments
|
||||
- Number of new digests analyzed per day
|
||||
- Fair use on deployments
|
||||
```
|
||||
|
||||
This prevents:
|
||||
- "Pay for security" anti-pattern
|
||||
- Per-project/per-seat billing landmines
|
||||
- Feature fragmentation across tiers
|
||||
|
||||
**Implementation Requirements:**
|
||||
- No feature flags tied to billing tier
|
||||
- Quota enforcement is transparent (clear error messages)
|
||||
- Usage metrics exposed for customer visibility
|
||||
- Overage handling is graceful (soft limits with warnings)
|
||||
|
||||
### Principle 5: Offline-First Operation
|
||||
|
||||
```
|
||||
INVARIANT: All core operations MUST work in air-gapped environments.
|
||||
```
|
||||
|
||||
Implications:
|
||||
- No runtime calls to external APIs for core decisions
|
||||
- Vulnerability data synced via mirror bundles
|
||||
- Plugins may require connectivity; core does not
|
||||
- Evidence packets exportable for external audit
|
||||
|
||||
**Implementation Requirements:**
|
||||
- Core decision logic has no external HTTP calls
|
||||
- All external data is pre-synced and cached
|
||||
- Plugin connectivity requirements are declared in manifest
|
||||
- Offline mode is explicit configuration, not degraded fallback
|
||||
|
||||
### Principle 6: Immutable Generated Artifacts
|
||||
|
||||
```
|
||||
INVARIANT: Every deployment generates and stores immutable artifacts.
|
||||
```
|
||||
|
||||
Generated artifacts:
|
||||
- `compose.stella.lock.yml`: Pinned digests, resolved env refs
|
||||
- `deploy.stella.script.dll`: Compiled C# script (or hash reference)
|
||||
- `release.evidence.json`: Decision record
|
||||
- `stella.version.json`: Version sticker placed on target
|
||||
|
||||
Version sticker enables:
|
||||
- Drift detection (expected vs actual)
|
||||
- Audit trail on target host
|
||||
- Rollback reference
|
||||
|
||||
**Implementation Requirements:**
|
||||
- Artifacts are content-addressed (hash in filename or metadata)
|
||||
- Artifacts are stored before deployment execution
|
||||
- Artifact storage is immutable (no overwrites)
|
||||
- Version sticker is atomic write on target
|
||||
|
||||
---
|
||||
|
||||
## Architectural Invariants (Enforced by Design)
|
||||
|
||||
These invariants are enforced through database constraints, code architecture, and operational controls.
|
||||
|
||||
| Invariant | Enforcement Mechanism |
|
||||
|-----------|----------------------|
|
||||
| Digests are immutable | Database constraint: digest column is unique, no updates |
|
||||
| Evidence packets are append-only | Evidence table has no UPDATE/DELETE permissions |
|
||||
| Secrets never in database | Vault integration; only references stored |
|
||||
| Plugins cannot bypass policy | Policy evaluation in core, not plugin |
|
||||
| Multi-tenant isolation | `tenant_id` FK on all tables; row-level security |
|
||||
| Workflow state is auditable | State transitions logged; no direct state manipulation |
|
||||
| Approvals are tamper-evident | Approval records are signed and append-only |
|
||||
|
||||
### Database Enforcement
|
||||
|
||||
```sql
|
||||
-- Example: Evidence table with no UPDATE/DELETE
|
||||
CREATE TABLE release.evidence_packets (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||||
promotion_id UUID NOT NULL REFERENCES release.promotions(id),
|
||||
content_hash TEXT NOT NULL,
|
||||
content JSONB NOT NULL,
|
||||
signature TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
-- No updated_at column; immutable by design
|
||||
);
|
||||
|
||||
-- Revoke UPDATE/DELETE from application role
|
||||
REVOKE UPDATE, DELETE ON release.evidence_packets FROM app_role;
|
||||
```
|
||||
|
||||
### Code Architecture Enforcement
|
||||
|
||||
```csharp
|
||||
// Policy evaluation is ALWAYS in core, never delegated to plugins
|
||||
public sealed class PromotionDecisionEngine
|
||||
{
|
||||
// Plugins provide gate implementations, but core orchestrates evaluation
|
||||
public async Task<DecisionResult> EvaluateAsync(
|
||||
Promotion promotion,
|
||||
IReadOnlyList<IGateProvider> gates,
|
||||
CancellationToken ct)
|
||||
{
|
||||
// Core controls evaluation order and aggregation
|
||||
var results = new List<GateResult>();
|
||||
foreach (var gate in gates)
|
||||
{
|
||||
// Plugin provides evaluation logic
|
||||
var result = await gate.EvaluateAsync(promotion, ct);
|
||||
results.Add(result);
|
||||
|
||||
// Core decides how to aggregate (plugins cannot override)
|
||||
if (result.IsBlocking && _policy.FailFast)
|
||||
break;
|
||||
}
|
||||
|
||||
// Core makes final decision
|
||||
return _decisionAggregator.Aggregate(results);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Document Conventions
|
||||
|
||||
Throughout the Release Orchestrator documentation:
|
||||
|
||||
- **MUST**: Mandatory requirement; non-compliance is a bug
|
||||
- **SHOULD**: Recommended but not mandatory; deviation requires justification
|
||||
- **MAY**: Optional; implementation decision
|
||||
- **Entity names**: `PascalCase` (e.g., `ReleaseBundle`)
|
||||
- **Table names**: `snake_case` (e.g., `release_bundles`)
|
||||
- **API paths**: `/api/v1/resource-name`
|
||||
- **Module names**: `kebab-case` (e.g., `release-manager`)
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [Key Architectural Decisions](decisions.md)
|
||||
- [Module Architecture](../modules/overview.md)
|
||||
- [Security Architecture](../security/overview.md)
|
||||
Reference in New Issue
Block a user