128 lines
4.7 KiB
Go
128 lines
4.7 KiB
Go
package debugbundle
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/eric/notarius/internal/core/artifacts"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/core/fileio"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
|
)
|
|
|
|
const (
|
|
ArtifactInvocationMetadata = "invocation.json"
|
|
ArtifactEffectiveConfig = "effective-config.json"
|
|
ArtifactResolvedPipeline = "resolved-pipeline.json"
|
|
ArtifactResolvedReferences = "resolved-references.json"
|
|
ArtifactCheckpointEvents = "checkpoint-events.json"
|
|
ArtifactRunManifest = "run-manifest.json"
|
|
ArtifactChunkPlan = "chunk-plan.json"
|
|
ArtifactRunReport = "run-report.json"
|
|
ArtifactWarnings = "warnings.json"
|
|
ArtifactErrorLog = "error.log"
|
|
)
|
|
|
|
type RedactedSummaryPayload interface{ RedactedSummaryPayload() any }
|
|
type RedactedResolvedPipelinePayload interface {
|
|
RedactedResolvedPipelinePayload() pipeline.ResolvedPipeline
|
|
}
|
|
type Invocation struct {
|
|
Operation string `json:"operation"`
|
|
PipelineID string `json:"pipeline_id,omitempty"`
|
|
PipelineDigest string `json:"pipeline_digest,omitempty"`
|
|
Resume bool `json:"resume,omitempty"`
|
|
InputPath string `json:"input_path,omitempty"`
|
|
ConfigPath string `json:"config_path,omitempty"`
|
|
ConfigSource string `json:"config_source,omitempty"`
|
|
OnlyLanes []string `json:"only_lanes,omitempty"`
|
|
ChunkCacheOverride string `json:"chunk_cache_override,omitempty"`
|
|
RunID string `json:"run_id"`
|
|
StartedAt time.Time `json:"started_at"`
|
|
}
|
|
type RunReport struct {
|
|
RunID string `json:"run_id"`
|
|
PipelineID string `json:"pipeline_id"`
|
|
OutputPath string `json:"output_path,omitempty"`
|
|
DebugPath string `json:"debug_path,omitempty"`
|
|
Succeeded bool `json:"succeeded"`
|
|
OutputCount int `json:"output_count"`
|
|
RejectedCount int `json:"rejected_count"`
|
|
WarningCount int `json:"warning_count"`
|
|
ValidationStatus string `json:"validation_status,omitempty"`
|
|
}
|
|
type SummaryWriter struct {
|
|
root, runID string
|
|
createdAt time.Time
|
|
}
|
|
|
|
func (w *SummaryWriter) WriteInvocation(payload Invocation) error {
|
|
if w == nil {
|
|
return fmt.Errorf("debug summary writer must not be nil")
|
|
}
|
|
if payload.RunID == "" {
|
|
payload.RunID = w.runID
|
|
}
|
|
if payload.StartedAt.IsZero() {
|
|
payload.StartedAt = w.createdAt
|
|
}
|
|
return w.writeJSON(ArtifactInvocationMetadata, payload)
|
|
}
|
|
func (w *SummaryWriter) WriteRedactedEffectiveConfig(payload RedactedSummaryPayload) error {
|
|
if payload == nil {
|
|
return fmt.Errorf("redacted summary payload must not be nil")
|
|
}
|
|
return w.writeJSON(ArtifactEffectiveConfig, payload.RedactedSummaryPayload())
|
|
}
|
|
func (w *SummaryWriter) WriteResolvedPipeline(payload RedactedResolvedPipelinePayload) error {
|
|
if payload == nil {
|
|
return fmt.Errorf("redacted resolved pipeline payload must not be nil")
|
|
}
|
|
return w.writeJSON(ArtifactResolvedPipeline, payload.RedactedResolvedPipelinePayload())
|
|
}
|
|
func (w *SummaryWriter) WriteResolvedReferences(v []artifacts.ReferenceProvenance) error {
|
|
return w.writeJSON(ArtifactResolvedReferences, v)
|
|
}
|
|
func (w *SummaryWriter) WriteCheckpointEvents(v []pipeline.CheckpointEvent) error {
|
|
return w.writeJSON(ArtifactCheckpointEvents, v)
|
|
}
|
|
func (w *SummaryWriter) WriteRunManifest(v artifacts.RunManifest) error {
|
|
return w.writeJSON(ArtifactRunManifest, v)
|
|
}
|
|
func (w *SummaryWriter) WriteChunkPlan(v artifacts.ChunkPlanSummary) error {
|
|
return w.writeJSON(ArtifactChunkPlan, v)
|
|
}
|
|
func (w *SummaryWriter) WriteRunReport(v RunReport) error { return w.writeJSON(ArtifactRunReport, v) }
|
|
func (w *SummaryWriter) WriteWarnings(v []contracts.Warning) error {
|
|
return w.writeJSON(ArtifactWarnings, v)
|
|
}
|
|
func (w *SummaryWriter) WriteError(message string) error {
|
|
return w.writeBytes(ArtifactErrorLog, []byte(message+"\n"))
|
|
}
|
|
func (w *SummaryWriter) writeJSON(name string, v any) error {
|
|
if w == nil {
|
|
return fmt.Errorf("debug summary writer must not be nil")
|
|
}
|
|
if err := fileio.WriteJSON(w.root, summaryName(name), v, 0o700, 0o600); err != nil {
|
|
return fmt.Errorf("write debug summary artifact %q: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
func (w *SummaryWriter) writeBytes(name string, v []byte) error {
|
|
if w == nil {
|
|
return fmt.Errorf("debug summary writer must not be nil")
|
|
}
|
|
if err := fileio.WriteBytes(w.root, summaryName(name), v, 0o700, 0o600); err != nil {
|
|
return fmt.Errorf("write debug summary artifact %q: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
func summaryName(name string) string {
|
|
name = strings.TrimSpace(name)
|
|
if name == "" || strings.ContainsAny(name, "/\\") {
|
|
return "../invalid"
|
|
}
|
|
return name
|
|
}
|