Add dummy LLM provider, update Concelier sources and JobEngine endpoints
- AdvisoryAI: DummyLlmProvider for offline/testing scenarios, wire in LlmProviderFactory - Concelier: source definitions, registry, and management endpoint updates - JobEngine: approval and release endpoint updates - etc/llm-providers/dummy.yaml config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -310,53 +310,60 @@ public static class ApprovalEndpoints
|
||||
}
|
||||
|
||||
// ---- Seed Data ----
|
||||
// Generates relative dates so approvals always look fresh regardless of when the service starts.
|
||||
|
||||
internal static class SeedData
|
||||
{
|
||||
private static string Ago(int hours) => DateTimeOffset.UtcNow.AddHours(-hours).ToString("o");
|
||||
private static string FromNow(int hours) => DateTimeOffset.UtcNow.AddHours(hours).ToString("o");
|
||||
|
||||
public static readonly List<ApprovalDto> Approvals = new()
|
||||
{
|
||||
// ── Pending: 1/2 approved, gates OK, normal priority ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-001", ReleaseId = "rel-001", ReleaseName = "API Gateway", ReleaseVersion = "2.1.0",
|
||||
Id = "apr-001", ReleaseId = "rel-001", ReleaseName = "API Gateway", ReleaseVersion = "2.4.1",
|
||||
SourceEnvironment = "staging", TargetEnvironment = "production",
|
||||
RequestedBy = "alice.johnson", RequestedAt = "2026-01-12T08:00:00Z",
|
||||
RequestedBy = "alice.johnson", RequestedAt = Ago(3),
|
||||
Urgency = "normal", Justification = "Scheduled release with new rate limiting feature and bug fixes.",
|
||||
Status = "pending", CurrentApprovals = 1, RequiredApprovals = 2, GatesPassed = true,
|
||||
ExpiresAt = "2026-01-14T08:00:00Z",
|
||||
ExpiresAt = FromNow(45),
|
||||
GateResults = new()
|
||||
{
|
||||
new() { GateId = "g1", GateName = "Security Scan", Type = "security", Status = "passed", Message = "No vulnerabilities found", EvaluatedAt = "2026-01-12T08:05:00Z" },
|
||||
new() { GateId = "g2", GateName = "Policy Compliance", Type = "policy", Status = "passed", Message = "All policies satisfied", EvaluatedAt = "2026-01-12T08:06:00Z" },
|
||||
new() { GateId = "g3", GateName = "Quality Gates", Type = "quality", Status = "passed", Message = "Code coverage: 85%", EvaluatedAt = "2026-01-12T08:07:00Z" },
|
||||
new() { GateId = "g1", GateName = "Security Scan", Type = "security", Status = "passed", Message = "No vulnerabilities found", EvaluatedAt = Ago(3) },
|
||||
new() { GateId = "g2", GateName = "Policy Compliance", Type = "policy", Status = "passed", Message = "All policies satisfied", EvaluatedAt = Ago(3) },
|
||||
new() { GateId = "g3", GateName = "Quality Gates", Type = "quality", Status = "passed", Message = "Code coverage: 85%", EvaluatedAt = Ago(3) },
|
||||
},
|
||||
Actions = new()
|
||||
{
|
||||
new() { Id = "act-1", ApprovalId = "apr-001", Action = "approved", Actor = "bob.smith", Comment = "Looks good, tests are passing.", Timestamp = "2026-01-12T09:30:00Z" },
|
||||
new() { Id = "act-1", ApprovalId = "apr-001", Action = "approved", Actor = "bob.smith", Comment = "Looks good, tests are passing.", Timestamp = Ago(2) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
new() { Id = "u1", Name = "Bob Smith", Email = "bob.smith@example.com", HasApproved = true, ApprovedAt = "2026-01-12T09:30:00Z" },
|
||||
new() { Id = "u1", Name = "Bob Smith", Email = "bob.smith@example.com", HasApproved = true, ApprovedAt = Ago(2) },
|
||||
new() { Id = "u2", Name = "Carol Davis", Email = "carol.davis@example.com" },
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "api-gateway", Version = "2.1.0", Digest = "sha256:abc123def456..." },
|
||||
new() { Name = "rate-limiter", Version = "1.0.5", Digest = "sha256:789xyz012..." },
|
||||
new() { Name = "api-gateway", Version = "2.4.1", Digest = "sha256:abc123def456" },
|
||||
new() { Name = "rate-limiter", Version = "1.0.5", Digest = "sha256:789xyz012abc" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Pending: 0/2 approved, gates FAILING, high priority ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-002", ReleaseId = "rel-002", ReleaseName = "User Service", ReleaseVersion = "3.0.0-rc1",
|
||||
SourceEnvironment = "staging", TargetEnvironment = "production",
|
||||
RequestedBy = "david.wilson", RequestedAt = "2026-01-12T10:00:00Z",
|
||||
RequestedBy = "david.wilson", RequestedAt = Ago(1),
|
||||
Urgency = "high", Justification = "Critical fix for user authentication timeout issue.",
|
||||
Status = "pending", CurrentApprovals = 0, RequiredApprovals = 2, GatesPassed = false,
|
||||
ExpiresAt = "2026-01-13T10:00:00Z",
|
||||
ExpiresAt = FromNow(23),
|
||||
GateResults = new()
|
||||
{
|
||||
new() { GateId = "g1", GateName = "Security Scan", Type = "security", Status = "warning", Message = "2 low severity vulnerabilities", EvaluatedAt = "2026-01-12T10:05:00Z" },
|
||||
new() { GateId = "g2", GateName = "Policy Compliance", Type = "policy", Status = "passed", Message = "All policies satisfied", EvaluatedAt = "2026-01-12T10:06:00Z" },
|
||||
new() { GateId = "g3", GateName = "Quality Gates", Type = "quality", Status = "failed", Message = "Code coverage: 72%", EvaluatedAt = "2026-01-12T10:07:00Z" },
|
||||
new() { GateId = "g1", GateName = "Security Scan", Type = "security", Status = "warning", Message = "2 low severity vulnerabilities", EvaluatedAt = Ago(1) },
|
||||
new() { GateId = "g2", GateName = "Policy Compliance", Type = "policy", Status = "passed", Message = "All policies satisfied", EvaluatedAt = Ago(1) },
|
||||
new() { GateId = "g3", GateName = "Quality Gates", Type = "quality", Status = "failed", Message = "Code coverage: 72% (min 80%)", EvaluatedAt = Ago(1) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
@@ -365,43 +372,95 @@ public static class ApprovalEndpoints
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "user-service", Version = "3.0.0-rc1", Digest = "sha256:user123..." },
|
||||
new() { Name = "user-service", Version = "3.0.0-rc1", Digest = "sha256:user123def456" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Pending: 0/1 approved, gates OK, critical, expiring soon ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-005", ReleaseId = "rel-005", ReleaseName = "Auth Service", ReleaseVersion = "1.8.3-hotfix",
|
||||
SourceEnvironment = "staging", TargetEnvironment = "production",
|
||||
RequestedBy = "frank.miller", RequestedAt = Ago(6),
|
||||
Urgency = "critical", Justification = "Hotfix: OAuth token refresh loop causing 503 cascade.",
|
||||
Status = "pending", CurrentApprovals = 0, RequiredApprovals = 1, GatesPassed = true,
|
||||
ExpiresAt = FromNow(2),
|
||||
GateResults = new()
|
||||
{
|
||||
new() { GateId = "g1", GateName = "Security Scan", Type = "security", Status = "passed", Message = "No vulnerabilities", EvaluatedAt = Ago(6) },
|
||||
new() { GateId = "g2", GateName = "Policy Compliance", Type = "policy", Status = "passed", Message = "Hotfix policy waiver applied", EvaluatedAt = Ago(6) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
new() { Id = "u4", Name = "Grace Lee", Email = "grace.lee@example.com" },
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "auth-service", Version = "1.8.3-hotfix", Digest = "sha256:auth789ghi012" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Pending: dev → staging, gates OK, low priority ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-006", ReleaseId = "rel-006", ReleaseName = "Billing Dashboard", ReleaseVersion = "4.2.0",
|
||||
SourceEnvironment = "dev", TargetEnvironment = "staging",
|
||||
RequestedBy = "alice.johnson", RequestedAt = Ago(12),
|
||||
Urgency = "low", Justification = "New billing analytics dashboard with chart components.",
|
||||
Status = "pending", CurrentApprovals = 0, RequiredApprovals = 1, GatesPassed = true,
|
||||
ExpiresAt = FromNow(60),
|
||||
GateResults = new()
|
||||
{
|
||||
new() { GateId = "g1", GateName = "Security Scan", Type = "security", Status = "passed", Message = "Clean scan", EvaluatedAt = Ago(12) },
|
||||
new() { GateId = "g2", GateName = "Quality Gates", Type = "quality", Status = "passed", Message = "Coverage 91%", EvaluatedAt = Ago(12) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
new() { Id = "u3", Name = "Emily Chen", Email = "emily.chen@example.com" },
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "billing-dashboard", Version = "4.2.0", Digest = "sha256:bill456def789" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Approved (completed): critical hotfix ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-003", ReleaseId = "rel-003", ReleaseName = "Payment Gateway", ReleaseVersion = "1.5.2",
|
||||
SourceEnvironment = "dev", TargetEnvironment = "staging",
|
||||
RequestedBy = "frank.miller", RequestedAt = "2026-01-11T14:00:00Z",
|
||||
RequestedBy = "frank.miller", RequestedAt = Ago(48),
|
||||
Urgency = "critical", Justification = "Emergency fix for payment processing failure.",
|
||||
Status = "approved", CurrentApprovals = 2, RequiredApprovals = 2, GatesPassed = true,
|
||||
ScheduledTime = "2026-01-12T06:00:00Z", ExpiresAt = "2026-01-12T14:00:00Z",
|
||||
ScheduledTime = Ago(46), ExpiresAt = Ago(24),
|
||||
Actions = new()
|
||||
{
|
||||
new() { Id = "act-2", ApprovalId = "apr-003", Action = "approved", Actor = "carol.davis", Comment = "Urgent fix approved.", Timestamp = "2026-01-11T14:30:00Z" },
|
||||
new() { Id = "act-3", ApprovalId = "apr-003", Action = "approved", Actor = "grace.lee", Comment = "Confirmed, proceed.", Timestamp = "2026-01-11T15:00:00Z" },
|
||||
new() { Id = "act-2", ApprovalId = "apr-003", Action = "approved", Actor = "carol.davis", Comment = "Urgent fix approved.", Timestamp = Ago(47) },
|
||||
new() { Id = "act-3", ApprovalId = "apr-003", Action = "approved", Actor = "grace.lee", Comment = "Confirmed, proceed.", Timestamp = Ago(46) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
new() { Id = "u2", Name = "Carol Davis", Email = "carol.davis@example.com", HasApproved = true, ApprovedAt = "2026-01-11T14:30:00Z" },
|
||||
new() { Id = "u4", Name = "Grace Lee", Email = "grace.lee@example.com", HasApproved = true, ApprovedAt = "2026-01-11T15:00:00Z" },
|
||||
new() { Id = "u2", Name = "Carol Davis", Email = "carol.davis@example.com", HasApproved = true, ApprovedAt = Ago(47) },
|
||||
new() { Id = "u4", Name = "Grace Lee", Email = "grace.lee@example.com", HasApproved = true, ApprovedAt = Ago(46) },
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "payment-gateway", Version = "1.5.2", Digest = "sha256:pay456..." },
|
||||
new() { Name = "payment-gateway", Version = "1.5.2", Digest = "sha256:pay456abc789" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Rejected: missing tests ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-004", ReleaseId = "rel-004", ReleaseName = "Notification Service", ReleaseVersion = "2.0.0",
|
||||
SourceEnvironment = "staging", TargetEnvironment = "production",
|
||||
RequestedBy = "alice.johnson", RequestedAt = "2026-01-10T09:00:00Z",
|
||||
RequestedBy = "alice.johnson", RequestedAt = Ago(72),
|
||||
Urgency = "low", Justification = "Feature release with new email templates.",
|
||||
Status = "rejected", CurrentApprovals = 0, RequiredApprovals = 2, GatesPassed = true,
|
||||
ExpiresAt = "2026-01-12T09:00:00Z",
|
||||
ExpiresAt = Ago(24),
|
||||
Actions = new()
|
||||
{
|
||||
new() { Id = "act-4", ApprovalId = "apr-004", Action = "rejected", Actor = "bob.smith", Comment = "Missing integration tests.", Timestamp = "2026-01-10T11:00:00Z" },
|
||||
new() { Id = "act-4", ApprovalId = "apr-004", Action = "rejected", Actor = "bob.smith", Comment = "Missing integration tests for the email template renderer.", Timestamp = Ago(70) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
@@ -409,7 +468,32 @@ public static class ApprovalEndpoints
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "notification-service", Version = "2.0.0", Digest = "sha256:notify789..." },
|
||||
new() { Name = "notification-service", Version = "2.0.0", Digest = "sha256:notify789abc" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Approved: routine promotion ──
|
||||
new()
|
||||
{
|
||||
Id = "apr-007", ReleaseId = "rel-007", ReleaseName = "Config Service", ReleaseVersion = "1.12.0",
|
||||
SourceEnvironment = "staging", TargetEnvironment = "production",
|
||||
RequestedBy = "david.wilson", RequestedAt = Ago(96),
|
||||
Urgency = "normal", Justification = "Routine config service update with new environment variable support.",
|
||||
Status = "approved", CurrentApprovals = 2, RequiredApprovals = 2, GatesPassed = true,
|
||||
ExpiresAt = Ago(48),
|
||||
Actions = new()
|
||||
{
|
||||
new() { Id = "act-5", ApprovalId = "apr-007", Action = "approved", Actor = "emily.chen", Comment = "LGTM.", Timestamp = Ago(94) },
|
||||
new() { Id = "act-6", ApprovalId = "apr-007", Action = "approved", Actor = "bob.smith", Comment = "Approved.", Timestamp = Ago(93) },
|
||||
},
|
||||
Approvers = new()
|
||||
{
|
||||
new() { Id = "u3", Name = "Emily Chen", Email = "emily.chen@example.com", HasApproved = true, ApprovedAt = Ago(94) },
|
||||
new() { Id = "u1", Name = "Bob Smith", Email = "bob.smith@example.com", HasApproved = true, ApprovedAt = Ago(93) },
|
||||
},
|
||||
ReleaseComponents = new()
|
||||
{
|
||||
new() { Name = "config-service", Version = "1.12.0", Digest = "sha256:cfg012xyz345" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -232,22 +232,34 @@ public static class ReleaseEndpoints
|
||||
private static IResult CreateRelease([FromBody] CreateReleaseDto request, [FromServices] TimeProvider time)
|
||||
{
|
||||
var now = time.GetUtcNow();
|
||||
|
||||
// When versionId is provided, link to an existing version (copy its digest/components)
|
||||
ManagedReleaseDto? sourceVersion = null;
|
||||
if (!string.IsNullOrEmpty(request.VersionId))
|
||||
{
|
||||
sourceVersion = SeedData.Releases.FirstOrDefault(r => r.Id == request.VersionId);
|
||||
}
|
||||
|
||||
var release = new ManagedReleaseDto
|
||||
{
|
||||
Id = $"rel-{Guid.NewGuid():N}"[..11],
|
||||
Name = request.Name,
|
||||
Version = request.Version,
|
||||
Description = request.Description ?? "",
|
||||
Description = request.Description ?? sourceVersion?.Description ?? "",
|
||||
Status = "draft",
|
||||
CurrentEnvironment = null,
|
||||
TargetEnvironment = request.TargetEnvironment,
|
||||
ComponentCount = 0,
|
||||
TargetEnvironment = request.TargetEnvironment ?? sourceVersion?.TargetEnvironment,
|
||||
ComponentCount = sourceVersion?.ComponentCount ?? 0,
|
||||
CreatedAt = now,
|
||||
CreatedBy = "api",
|
||||
UpdatedAt = now,
|
||||
DeployedAt = null,
|
||||
DeploymentStrategy = request.DeploymentStrategy ?? "rolling",
|
||||
DeploymentStrategy = request.DeploymentStrategy ?? sourceVersion?.DeploymentStrategy ?? "rolling",
|
||||
};
|
||||
|
||||
// Add the new release to the in-memory store so it appears in list queries
|
||||
SeedData.Releases.Add(release);
|
||||
|
||||
return Results.Created($"/api/release-orchestrator/releases/{release.Id}", release);
|
||||
}
|
||||
|
||||
@@ -579,6 +591,7 @@ public static class ReleaseEndpoints
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required string Version { get; init; }
|
||||
public string? VersionId { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public string? TargetEnvironment { get; init; }
|
||||
public string? DeploymentStrategy { get; init; }
|
||||
|
||||
Reference in New Issue
Block a user