Connect processing preflight and output reporting
This commit is contained in:
76
internal/framework/preflight/preflight.go
Normal file
76
internal/framework/preflight/preflight.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// Package preflight checks resolved processing inputs and prepares output resources.
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/config"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/diagnostics"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/schema"
|
||||
)
|
||||
|
||||
// Input contains already acquired application and transcript inputs.
|
||||
type Input struct {
|
||||
Config *config.Config
|
||||
Transcript *schema.SourceTranscript
|
||||
Output diagnostics.OutputSelection
|
||||
InitialReports diagnostics.ReportBundle
|
||||
FailedReports diagnostics.ReportBundle
|
||||
Debug *DebugInput
|
||||
}
|
||||
|
||||
type DebugInput struct {
|
||||
WorkDir string
|
||||
RunID string
|
||||
Metadata diagnostics.InvocationMetadata
|
||||
EffectiveConfig []byte
|
||||
Secrets []string
|
||||
}
|
||||
|
||||
type Prepared struct {
|
||||
Output *diagnostics.OutputSession
|
||||
Debug *diagnostics.RunDirectory
|
||||
Warnings []error
|
||||
}
|
||||
|
||||
// Prepare validates invocation inputs and collisions before acquiring outputs.
|
||||
func Prepare(ctx context.Context, input Input) (*Prepared, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if input.Config == nil {
|
||||
return nil, fmt.Errorf("application configuration is required")
|
||||
}
|
||||
if input.Transcript == nil {
|
||||
return nil, fmt.Errorf("transcript is required")
|
||||
}
|
||||
session, err := diagnostics.SelectOutput(input.Output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := session.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
_ = session.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := session.Initialize(input.InitialReports, input.FailedReports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, session.Finish(err, nil, input.FailedReports, func([]diagnostics.FileFailure) diagnostics.ReportBundle { return input.FailedReports })
|
||||
}
|
||||
result := &Prepared{Output: session}
|
||||
if input.Debug != nil {
|
||||
result.Debug, result.Warnings = session.PrepareDebug(input.Debug.WorkDir, input.Debug.RunID, input.Debug.Metadata, input.Debug.EffectiveConfig, input.Debug.Secrets...)
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, session.Finish(err, nil, input.FailedReports, func([]diagnostics.FileFailure) diagnostics.ReportBundle { return input.FailedReports })
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
48
internal/framework/preflight/preflight_test.go
Normal file
48
internal/framework/preflight/preflight_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/config"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/diagnostics"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/schema"
|
||||
)
|
||||
|
||||
func TestReadinessAndCollisionPrecedeOutputPreparation(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
output := filepath.Join(dir, "output.json")
|
||||
if _, err := Prepare(context.Background(), Input{Config: &config.Config{}, Output: diagnostics.OutputSelection{TranscriptPath: output}}); err == nil {
|
||||
t.Fatal("missing transcript accepted")
|
||||
}
|
||||
if _, err := os.Stat(output); !os.IsNotExist(err) {
|
||||
t.Fatalf("output created: %v", err)
|
||||
}
|
||||
if _, err := Prepare(context.Background(), Input{Config: &config.Config{}, Transcript: &schema.SourceTranscript{}, Output: diagnostics.OutputSelection{TranscriptPath: output, ProtectedPaths: []string{output}}}); err == nil {
|
||||
t.Fatal("collision accepted")
|
||||
}
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil || len(entries) != 0 {
|
||||
t.Fatalf("prepared before check: %v %v", entries, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionalDebugFailureDoesNotPreventPreparation(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
blocked := filepath.Join(dir, "file")
|
||||
if err := os.WriteFile(blocked, []byte("x"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := Prepare(context.Background(), Input{Config: &config.Config{}, Transcript: &schema.SourceTranscript{}, Output: diagnostics.OutputSelection{TranscriptPath: filepath.Join(dir, "output")}, Debug: &DebugInput{WorkDir: blocked, RunID: "run"}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(result.Warnings) == 0 || result.Debug != nil {
|
||||
t.Fatalf("debug=%v warnings=%v", result.Debug, result.Warnings)
|
||||
}
|
||||
if err := result.Output.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user