Enforce canonical Notarius bundle paths
This commit is contained in:
@@ -2,6 +2,7 @@ package stage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -300,6 +301,66 @@ func TestExtractStageResumeValidationAcceptsCurrentImmutableResult(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractStageAdapterResultIsImmediatelyReusableAndCatalogVisible(t *testing.T) {
|
||||
env, m, fake := setupExtractEnv(t)
|
||||
producerRunID := m.RunID
|
||||
receiptFixture := filepath.Join(t.TempDir(), "receipt.json")
|
||||
receipt, err := json.Marshal(map[string]any{
|
||||
"schema_version": notarius.ReceiptSchemaVersion,
|
||||
"run_id": "notarius-run-1", "pipeline_id": "dnd-session",
|
||||
"output_directory": fake.Result.BundleRoot, "index_file": "index.json",
|
||||
"normalized_output_count": 2, "rejected_output_count": 0, "warning_count": 0,
|
||||
"validation_status": "approved", "future_field": true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal(receipt) error = %v", err)
|
||||
}
|
||||
if err := os.WriteFile(receiptFixture, receipt, 0o644); err != nil {
|
||||
t.Fatalf("WriteFile(receipt fixture) error = %v", err)
|
||||
}
|
||||
if err := os.WriteFile(env.Config.Pipeline.Notarius.Binary, []byte("#!/bin/sh\ncat \"$NARRATIO_NOTARIUS_RECEIPT_FIXTURE\"\n"), 0o755); err != nil {
|
||||
t.Fatalf("WriteFile(notarius helper) error = %v", err)
|
||||
}
|
||||
t.Setenv("NARRATIO_NOTARIUS_RECEIPT_FIXTURE", receiptFixture)
|
||||
env.Notarius = notarius.NewSubprocessRunner()
|
||||
|
||||
result, err := (extractStage{}).Run(context.Background(), env, m)
|
||||
if err != nil {
|
||||
t.Fatalf("Run() error = %v", err)
|
||||
}
|
||||
durableIndex := filepath.Join(result.Metadata["bundle_root"].(string), "index.json")
|
||||
if len(result.Outputs) != 2 || result.Outputs[1].AbsolutePath != durableIndex {
|
||||
t.Fatalf("outputs = %#v, want canonical durable index %q", result.Outputs, durableIndex)
|
||||
}
|
||||
recordSucceededExtractResult(m, producerRunID, result)
|
||||
m.RunID = "20260810T020304Z-fedcba98"
|
||||
|
||||
validation, err := (extractStage{}).ValidateResume(context.Background(), env, m)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateResume() error = %v", err)
|
||||
}
|
||||
if !validation.Resumable {
|
||||
t.Fatalf("validation = %#v, want resumable", validation)
|
||||
}
|
||||
definition := env.Config.Pipeline.Notarius.Outputs["npc_registry"]
|
||||
definitions := map[string]artifacts.ExtractionArtifactDefinition{
|
||||
"npc_registry": {
|
||||
LaneID: definition.LaneID, PipelineID: env.Config.Pipeline.Notarius.PipelineID,
|
||||
MediaType: definition.MediaType, SchemaID: definition.SchemaID,
|
||||
SchemaVersion: definition.SchemaVersion, ModuleKey: definition.ModuleKey,
|
||||
},
|
||||
}
|
||||
catalog := artifacts.NewArtifactCatalog()
|
||||
if err := catalog.RegisterExtractionArtifacts(definitions); err != nil {
|
||||
t.Fatalf("RegisterExtractionArtifacts() error = %v", err)
|
||||
}
|
||||
catalog.HydrateExtractionArtifacts(sessionPathsForEnv(env, m.SessionID), m, definitions)
|
||||
entry, ok := catalog.Lookup(artifacts.ExtractionArtifactSourceID("npc_registry"))
|
||||
if !ok || !entry.Available || entry.Path != result.Outputs[0].AbsolutePath || entry.ProducerRunID != producerRunID {
|
||||
t.Fatalf("hydrated extraction entry = %#v, %v", entry, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractStageResumeValidationRejectsObsoleteResults(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -378,6 +439,10 @@ func seedSucceededExtractResult(t *testing.T, env *Env, m *manifest.Manifest) {
|
||||
if err != nil {
|
||||
t.Fatalf("Run() error = %v", err)
|
||||
}
|
||||
recordSucceededExtractResult(m, producerRunID, result)
|
||||
}
|
||||
|
||||
func recordSucceededExtractResult(m *manifest.Manifest, producerRunID string, result *StageResult) {
|
||||
records := make([]manifest.ArtifactRecord, 0, len(result.Outputs))
|
||||
for _, output := range result.Outputs {
|
||||
records = append(records, manifest.ArtifactRecord{
|
||||
@@ -461,7 +526,7 @@ func setupExtractEnv(t *testing.T) (*Env, *manifest.Manifest, *notarius.FakeRunn
|
||||
t.Fatalf("MkdirAll(bundle unknown) error = %v", err)
|
||||
}
|
||||
files := map[string]string{
|
||||
"index.json": `{ "manifest_file": "manifest.json" }`,
|
||||
"index.json": `{"manifest_file":"manifest.json","output_files":[{"lane_id":"npc-registry","file":"lanes/npc.json","media_type":"application/json","module_key":"dnd/npc-registry","schema_id":"notarius.dnd.npc_registry","schema_version":"v1","future_field":true},{"lane_id":"unconfigured","file":"lanes/unconfigured.json"}],"rejected_file":"rejected.json","warnings_file":"warnings.json","future_field":true}`,
|
||||
"manifest.json": `{}`,
|
||||
"rejected.json": `{"rejected":[]}`,
|
||||
"warnings.json": `{"warnings":[]}`,
|
||||
|
||||
Reference in New Issue
Block a user