feat: Implement Filesystem and MongoDB provenance writers for PackRun execution context
Some checks failed
Airgap Sealed CI Smoke / sealed-smoke (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled

- Added `FilesystemPackRunProvenanceWriter` to write provenance manifests to the filesystem.
- Introduced `MongoPackRunArtifactReader` to read artifacts from MongoDB.
- Created `MongoPackRunProvenanceWriter` to store provenance manifests in MongoDB.
- Developed unit tests for filesystem and MongoDB provenance writers.
- Established `ITimelineEventStore` and `ITimelineIngestionService` interfaces for timeline event handling.
- Implemented `TimelineIngestionService` to validate and persist timeline events with hashing.
- Created PostgreSQL schema and migration scripts for timeline indexing.
- Added dependency injection support for timeline indexer services.
- Developed tests for timeline ingestion and schema validation.
This commit is contained in:
StellaOps Bot
2025-11-30 15:38:14 +02:00
parent 8f54ffa203
commit 17d45a6d30
276 changed files with 8618 additions and 688 deletions

View File

@@ -0,0 +1,16 @@
namespace StellaOps.TaskRunner.Core.Execution;
public interface IPackRunArtifactReader
{
Task<IReadOnlyList<PackRunArtifactRecord>> ListAsync(string runId, CancellationToken cancellationToken);
}
public sealed record PackRunArtifactRecord(
string Name,
string Type,
string? SourcePath,
string? StoredPath,
string Status,
string? Notes,
DateTimeOffset CapturedAt,
string? ExpressionJson = null);

View File

@@ -0,0 +1,6 @@
namespace StellaOps.TaskRunner.Core.Execution;
public interface IPackRunProvenanceWriter
{
Task WriteAsync(PackRunExecutionContext context, PackRunState state, CancellationToken cancellationToken);
}

View File

@@ -2,21 +2,24 @@ using StellaOps.TaskRunner.Core.Planning;
namespace StellaOps.TaskRunner.Core.Execution;
public sealed class PackRunExecutionContext
{
public PackRunExecutionContext(string runId, TaskPackPlan plan, DateTimeOffset requestedAt)
{
ArgumentException.ThrowIfNullOrWhiteSpace(runId);
ArgumentNullException.ThrowIfNull(plan);
RunId = runId;
Plan = plan;
RequestedAt = requestedAt;
}
public string RunId { get; }
public TaskPackPlan Plan { get; }
public DateTimeOffset RequestedAt { get; }
}
public sealed class PackRunExecutionContext
{
public PackRunExecutionContext(string runId, TaskPackPlan plan, DateTimeOffset requestedAt, string? tenantId = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(runId);
ArgumentNullException.ThrowIfNull(plan);
RunId = runId;
Plan = plan;
RequestedAt = requestedAt;
TenantId = string.IsNullOrWhiteSpace(tenantId) ? null : tenantId.Trim();
}
public string RunId { get; }
public TaskPackPlan Plan { get; }
public DateTimeOffset RequestedAt { get; }
public string? TenantId { get; }
}

View File

@@ -11,16 +11,18 @@ public sealed record PackRunState(
DateTimeOffset RequestedAt,
DateTimeOffset CreatedAt,
DateTimeOffset UpdatedAt,
IReadOnlyDictionary<string, PackRunStepStateRecord> Steps)
{
public static PackRunState Create(
string runId,
IReadOnlyDictionary<string, PackRunStepStateRecord> Steps,
string? TenantId = null)
{
public static PackRunState Create(
string runId,
string planHash,
TaskPackPlan plan,
TaskPackPlanFailurePolicy failurePolicy,
DateTimeOffset requestedAt,
IReadOnlyDictionary<string, PackRunStepStateRecord> steps,
DateTimeOffset timestamp)
DateTimeOffset timestamp,
string? tenantId = null)
=> new(
runId,
planHash,
@@ -29,8 +31,9 @@ public sealed record PackRunState(
requestedAt,
timestamp,
timestamp,
new ReadOnlyDictionary<string, PackRunStepStateRecord>(new Dictionary<string, PackRunStepStateRecord>(steps, StringComparer.Ordinal)));
}
new ReadOnlyDictionary<string, PackRunStepStateRecord>(new Dictionary<string, PackRunStepStateRecord>(steps, StringComparer.Ordinal)),
tenantId);
}
public sealed record PackRunStepStateRecord(
string StepId,

View File

@@ -74,7 +74,8 @@ public static class PackRunStateFactory
failurePolicy,
context.RequestedAt,
stepRecords,
timestamp);
timestamp,
context.TenantId);
}
private static Dictionary<string, PackRunSimulationNode> IndexSimulation(IReadOnlyList<PackRunSimulationNode> nodes)

View File

@@ -0,0 +1,65 @@
using StellaOps.TaskRunner.Core.Planning;
namespace StellaOps.TaskRunner.Core.Execution;
public static class ProvenanceManifestFactory
{
public static ProvenanceManifest Create(PackRunExecutionContext context, PackRunState state, DateTimeOffset completedAt)
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(state);
var steps = state.Steps.Values
.OrderBy(step => step.StepId, StringComparer.Ordinal)
.Select(step => new ProvenanceStep(
step.StepId,
step.Kind.ToString(),
step.Status.ToString(),
step.Attempts,
step.LastTransitionAt,
step.StatusReason))
.ToList();
var outputs = context.Plan.Outputs
.Select(output => new ProvenanceOutput(output.Name, output.Type))
.ToList();
return new ProvenanceManifest(
context.RunId,
context.TenantId,
context.Plan.Hash,
context.Plan.Metadata.Name,
context.Plan.Metadata.Version,
context.Plan.Metadata.Description,
context.Plan.Metadata.Tags,
context.RequestedAt,
state.CreatedAt,
completedAt,
steps,
outputs);
}
}
public sealed record ProvenanceManifest(
string RunId,
string? TenantId,
string PlanHash,
string PackName,
string PackVersion,
string? PackDescription,
IReadOnlyList<string> PackTags,
DateTimeOffset RequestedAt,
DateTimeOffset CreatedAt,
DateTimeOffset CompletedAt,
IReadOnlyList<ProvenanceStep> Steps,
IReadOnlyList<ProvenanceOutput> Outputs);
public sealed record ProvenanceStep(
string Id,
string Kind,
string Status,
int Attempts,
DateTimeOffset? LastTransitionAt,
string? StatusReason);
public sealed record ProvenanceOutput(string Name, string Type);