Verify Notarius credential lifecycle
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/adapters/notarius"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/artifactmodel"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/artifactpolicy"
|
||||
@@ -485,6 +486,92 @@ func TestExtractLifecycleSkipsCurrentResumableResult(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractLifecycleCredentialChangesRemainResumable(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
before func(*testing.T) *configkit.Secret
|
||||
after func(*testing.T) *configkit.Secret
|
||||
}{
|
||||
{
|
||||
name: "added",
|
||||
after: func(t *testing.T) *configkit.Secret {
|
||||
return loadLifecycleNotariusCredential(t, "NARRATIO_LIFECYCLE_ADDED_KEY", "added-value")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "removed",
|
||||
before: func(t *testing.T) *configkit.Secret {
|
||||
return loadLifecycleNotariusCredential(t, "NARRATIO_LIFECYCLE_REMOVED_KEY", "removed-value")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "renamed",
|
||||
before: func(t *testing.T) *configkit.Secret {
|
||||
return loadLifecycleNotariusCredential(t, "NARRATIO_LIFECYCLE_FIRST_KEY", "first-value")
|
||||
},
|
||||
after: func(t *testing.T) *configkit.Secret {
|
||||
return loadLifecycleNotariusCredential(t, "NARRATIO_LIFECYCLE_SECOND_KEY", "second-value")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value rotated",
|
||||
before: func(t *testing.T) *configkit.Secret {
|
||||
return loadLifecycleNotariusCredential(t, "NARRATIO_LIFECYCLE_ROTATED_KEY", "first-value")
|
||||
},
|
||||
after: func(t *testing.T) *configkit.Secret {
|
||||
return loadLifecycleNotariusCredential(t, "NARRATIO_LIFECYCLE_ROTATED_KEY", "second-value")
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
cfg, env, runner := extractionLifecycleFixture(t, true)
|
||||
if test.before != nil {
|
||||
cfg.Pipeline.Notarius.LLMAPIKey = test.before(t)
|
||||
}
|
||||
analyzeRuns := 0
|
||||
plan := extractionLifecyclePlan(t, &analyzeRuns)
|
||||
if _, err := executeStages(context.Background(), cfg, plan, RunOptions{Env: env}); err != nil {
|
||||
t.Fatalf("initial executeStages() error = %v", err)
|
||||
}
|
||||
cfg.Pipeline.Notarius.LLMAPIKey = nil
|
||||
if test.after != nil {
|
||||
cfg.Pipeline.Notarius.LLMAPIKey = test.after(t)
|
||||
}
|
||||
resumed, err := executeStages(context.Background(), cfg, plan, RunOptions{Env: env})
|
||||
if err != nil {
|
||||
t.Fatalf("resume executeStages() error = %v", err)
|
||||
}
|
||||
if len(resumed.Executed) != 0 || len(resumed.Skipped) != 2 || len(runner.requests) != 1 || analyzeRuns != 1 {
|
||||
t.Fatalf("credential-only change reexecuted work: summary=%#v requests=%d analyze=%d", resumed, len(runner.requests), analyzeRuns)
|
||||
}
|
||||
loaded := loadLifecycleManifest(t, cfg)
|
||||
if loaded.Stages["extract"].Status != manifest.StatusSucceeded || loaded.Stages["analyze"].Status != manifest.StatusSucceeded {
|
||||
t.Fatalf("credential-only change invalidated stages: extract=%q analyze=%q", loaded.Stages["extract"].Status, loaded.Stages["analyze"].Status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreparedPipelineAndManifestExcludeNotariusCredentialValue(t *testing.T) {
|
||||
const name = "NARRATIO_LIFECYCLE_PERSISTED_KEY"
|
||||
const canary = "notarius-persisted-credential-canary"
|
||||
cfg, env, _ := extractionLifecycleFixture(t, true)
|
||||
cfg.Pipeline.Notarius.LLMAPIKey = loadLifecycleNotariusCredential(t, name, canary)
|
||||
if _, err := executeStages(context.Background(), cfg, prepareExtractLifecyclePlan(t), RunOptions{Env: env}); err != nil {
|
||||
t.Fatalf("executeStages() error = %v", err)
|
||||
}
|
||||
paths := artifacts.NewLocalStore(cfg.Pipeline.Workspace.Root).SessionPathsFor(cfg.Session.Campaign, cfg.Session.SessionID)
|
||||
for _, path := range []string{paths.ManifestPath, filepath.Join(paths.InputsDir, "pipeline.resolved.yml")} {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile(%q) error = %v", path, err)
|
||||
}
|
||||
if strings.Contains(string(data), canary) {
|
||||
t.Fatalf("persisted Narratio file %q contains the credential value", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractLifecycleRerunsAfterDirectTranscriptChange(t *testing.T) {
|
||||
cfg, env, runner := extractionLifecycleFixture(t, true)
|
||||
analyzeRuns := 0
|
||||
@@ -761,3 +848,17 @@ func extractionLifecycleFixture(t *testing.T, enabled bool) (*config.Config, *st
|
||||
runner := &materializingNotariusRunner{cfg: cfg.Pipeline.Notarius}
|
||||
return cfg, &stage.Env{Notarius: runner}, runner
|
||||
}
|
||||
|
||||
func loadLifecycleNotariusCredential(t *testing.T, name, value string) *configkit.Secret {
|
||||
t.Helper()
|
||||
t.Setenv(name, value)
|
||||
path := filepath.Join(t.TempDir(), "pipeline.yml")
|
||||
if err := os.WriteFile(path, []byte("whisperx:\n transcribe_url: https://transcription.example.test/transcribe\nnotarius:\n enabled: false\n llm_api_key: "+name+"\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pipeline, err := config.LoadPipeline(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return pipeline.Notarius.LLMAPIKey
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user