Verify shared provider credentials across both adapters
This commit is contained in:
244
internal/app/provider_credentials_integration_test.go
Normal file
244
internal/app/provider_credentials_integration_test.go
Normal file
@@ -0,0 +1,244 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
||||
)
|
||||
|
||||
const (
|
||||
sharedProviderName = "NARRATIO_SHARED_PROVIDER_KEY"
|
||||
auditaOnlyName = "NARRATIO_AUDITA_ONLY_KEY"
|
||||
sharedProviderKey = "synthetic-shared-provider-value"
|
||||
auditaOnlyKey = "synthetic-audita-only-value"
|
||||
)
|
||||
|
||||
func TestCommandsShareProviderCredentialAcrossAdapters(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
workspace := t.TempDir()
|
||||
secretsDir := filepath.Join(configDir, "secrets")
|
||||
for name, value := range map[string]string{
|
||||
sharedProviderName: sharedProviderKey,
|
||||
auditaOnlyName: auditaOnlyKey,
|
||||
} {
|
||||
restoreEnvAfterTest(t, name)
|
||||
if err := os.Unsetenv(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mustWriteSecretFile(t, filepath.Join(secretsDir, name), value+"\n")
|
||||
}
|
||||
fixture := writeProviderProcessWrapper(t)
|
||||
seriatim := writeSeriatimAppTestWrapper(t)
|
||||
configPath := filepath.Join(configDir, "pipeline.yml")
|
||||
campaignPath := writeAppTestCampaignConfig(t, configDir)
|
||||
sessionPath := filepath.Join(configDir, "session.yml")
|
||||
notariusConfig := filepath.Join(configDir, "notarius.yml")
|
||||
mustWriteTestFile(t, notariusConfig, "pipelines: {}\n")
|
||||
mustWriteTestFile(t, configPath, `workspace:
|
||||
root: `+workspace+`
|
||||
storage:
|
||||
backend: local
|
||||
whisperx:
|
||||
transcribe_url: https://example.com/transcribe
|
||||
seriatim:
|
||||
binary: `+seriatim+`
|
||||
audita:
|
||||
binary: `+fixture+`
|
||||
credentials: [`+sharedProviderName+`, `+auditaOnlyName+`]
|
||||
notarius:
|
||||
enabled: true
|
||||
binary: `+fixture+`
|
||||
config_path: `+notariusConfig+`
|
||||
pipeline_id: dnd-session
|
||||
credentials: [`+sharedProviderName+`]
|
||||
outputs:
|
||||
npc_registry:
|
||||
lane_id: npc-registry
|
||||
media_type: application/json
|
||||
schema_id: notarius.dnd.npc_registry
|
||||
schema_version: v1
|
||||
module_key: dnd/npc-registry
|
||||
notification:
|
||||
mode: noop
|
||||
`)
|
||||
mustWriteTestFile(t, sessionPath, `session_id: 2026-05-03
|
||||
campaign: sample-campaign
|
||||
inputs:
|
||||
audio_dir: ./audio
|
||||
speakers_file: ./speakers.yml
|
||||
autocorrect_file: ./autocorrect.yml
|
||||
glossary_file: ./glossary.yml
|
||||
`)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
if code := Execute([]string{"config", "show", "--config", configPath}, &stdout, &stderr); code != 0 {
|
||||
t.Fatalf("config show exit = %d; stderr=%q", code, stderr.String())
|
||||
}
|
||||
if !strings.Contains(stdout.String(), sharedProviderName) || !strings.Contains(stdout.String(), auditaOnlyName) {
|
||||
t.Fatalf("config show omitted reference names: %q", stdout.String())
|
||||
}
|
||||
assertNoProviderValues(t, stdout.Bytes(), stderr.Bytes())
|
||||
|
||||
workRoot := filepath.Join(workspace, "work", "sample-campaign", "2026-05-03")
|
||||
manifestPath := filepath.Join(workRoot, "manifest.json")
|
||||
basePath := filepath.Join(workRoot, "transcripts", "base.json")
|
||||
mustWriteTestFile(t, basePath, `{"schema":"seriatim-intermediate","segments":[]}`)
|
||||
seedCurrentBuiltInEvidence(t, manifestPath, "2026-05-03", "sample-campaign", "merge", artifacts.TranscriptOutputKindBase, artifacts.ArtifactTranscriptBase, basePath)
|
||||
mustWriteTestFile(t, filepath.Join(workRoot, "inputs", "glossary.yml"), "[]\n")
|
||||
args := []string{"--config", configPath, "--campaign-file", campaignPath, "--session", sessionPath}
|
||||
stdout.Reset()
|
||||
stderr.Reset()
|
||||
if code := Execute(append([]string{"run-stage", "polish", "2026-05-03", "--force"}, args...), &stdout, &stderr); code != 0 {
|
||||
t.Fatalf("polish exit = %d; stderr=%q", code, stderr.String())
|
||||
}
|
||||
assertNoProviderValues(t, stdout.Bytes(), stderr.Bytes())
|
||||
m, err := (&manifest.LocalStore{}).Load(context.Background(), manifestPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if polish := m.Stages["polish"]; polish == nil || len(polish.Outputs) != 1 || len(polish.Logs) != 5 {
|
||||
t.Fatalf("polish did not retain canonical transcript and ordinary reports: %#v", polish)
|
||||
}
|
||||
for _, name := range []string{"errors.yml", "recoveries.yml", "report.md"} {
|
||||
found := false
|
||||
for _, path := range m.Stages["polish"].Logs {
|
||||
found = found || filepath.Base(path) == name
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("missing polish report %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
trimmedPath := filepath.Join(workRoot, "transcripts", "final.trimmed.json")
|
||||
mustWriteTestFile(t, trimmedPath, `{"segments":[]}`)
|
||||
setCurrentBuiltInEvidence(t, m, "trim", artifacts.TranscriptOutputKindFinalTrimmed, artifacts.ArtifactTranscriptFinalTrimmed, trimmedPath)
|
||||
if err := (&manifest.LocalStore{}).Save(context.Background(), manifestPath, m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stdout.Reset()
|
||||
stderr.Reset()
|
||||
if code := Execute(append([]string{"run-stage", "extract", "2026-05-03", "--force"}, args...), &stdout, &stderr); code != 0 {
|
||||
t.Fatalf("extract exit = %d; stderr=%q", code, stderr.String())
|
||||
}
|
||||
assertNoProviderValues(t, stdout.Bytes(), stderr.Bytes())
|
||||
if !strings.Contains(stdout.String(), "stage=extract executed=1") {
|
||||
t.Fatalf("extract did not execute: %q", stdout.String())
|
||||
}
|
||||
redactedLogs := 0
|
||||
if err := filepath.WalkDir(workRoot, func(path string, entry os.DirEntry, walkErr error) error {
|
||||
if walkErr != nil || entry.IsDir() {
|
||||
return walkErr
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err == nil {
|
||||
assertNoProviderValues(t, data)
|
||||
if strings.HasSuffix(path, ".stderr.log") && bytes.Contains(data, []byte("<redacted>")) {
|
||||
redactedLogs++
|
||||
}
|
||||
}
|
||||
return err
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if redactedLogs < 2 {
|
||||
t.Fatalf("redacted subprocess logs = %d, want Audita and Notarius", redactedLogs)
|
||||
}
|
||||
}
|
||||
|
||||
func assertNoProviderValues(t *testing.T, content ...[]byte) {
|
||||
t.Helper()
|
||||
for _, data := range content {
|
||||
if bytes.Contains(data, []byte(sharedProviderKey)) || bytes.Contains(data, []byte(auditaOnlyKey)) {
|
||||
t.Fatal("credential value appeared in inspection or workspace output")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeProviderProcessWrapper(t *testing.T) string {
|
||||
t.Helper()
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(t.TempDir(), "provider-process.sh")
|
||||
if err := os.WriteFile(path, []byte("#!/bin/sh\nexec \""+exe+"\" -test.run=TestProviderCredentialProcessFixture -- \"$@\"\n"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func TestProviderCredentialProcessFixture(t *testing.T) {
|
||||
if !appHelperInvocation() {
|
||||
return
|
||||
}
|
||||
start := -1
|
||||
for i, arg := range os.Args {
|
||||
if arg == "--" {
|
||||
start = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if start < 0 || start >= len(os.Args) {
|
||||
os.Exit(2)
|
||||
}
|
||||
args := os.Args[start:]
|
||||
if os.Getenv(sharedProviderName) != sharedProviderKey {
|
||||
_, _ = os.Stderr.WriteString("shared credential not forwarded\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
switch args[0] {
|
||||
case "process":
|
||||
if os.Getenv(auditaOnlyName) != auditaOnlyKey {
|
||||
_, _ = os.Stderr.WriteString("Audita-only credential not forwarded\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
output := appSeriatimFlagValue(args, "--output")
|
||||
if output == "" {
|
||||
os.Exit(2)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(output), 0o755); err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
if err := os.WriteFile(output, []byte(`{"schema":"audita.processed.v1","segments":[]}`), 0o644); err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
for _, name := range []string{"errors.yml", "recoveries.yml", "report.md"} {
|
||||
if err := os.WriteFile(filepath.Join(filepath.Dir(output), name), []byte("status: completed\n"), 0o644); err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
case "run":
|
||||
if _, present := os.LookupEnv(auditaOnlyName); present {
|
||||
_, _ = os.Stderr.WriteString("Audita-only credential reached Notarius\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
root := appSeriatimFlagValue(args, "--output-dir")
|
||||
bundle := filepath.Join(root, "fixture-run")
|
||||
if err := os.MkdirAll(filepath.Join(bundle, "lanes"), 0o755); err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
for name, value := range map[string]string{
|
||||
"manifest.json": "{}", "rejected.json": `{"rejected":[]}`,
|
||||
"warnings.json": `{"schema_version":"notarius.warnings.v2","group_count":0,"occurrence_count":0,"groups":[]}`,
|
||||
"diagnostics.json": `{"schema_version":"notarius.diagnostics.v1","group_count":0,"occurrence_count":0,"truncated":false,"unrepresented_occurrence_count":0,"groups":[]}`,
|
||||
"lanes/npc.json": `{"records":[]}`,
|
||||
"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"}],"rejected_file":"rejected.json","warnings_file":"warnings.json","diagnostics_file":"diagnostics.json"}`,
|
||||
} {
|
||||
if err := os.WriteFile(filepath.Join(bundle, filepath.FromSlash(name)), []byte(value), 0o644); err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
_, _ = os.Stdout.WriteString(fmt.Sprintf(`{"schema_version":"notarius.run-result.v2","run_id":"fixture-run","pipeline_id":"dnd-session","output_directory":%q,"index_file":"index.json","normalized_output_count":1,"rejected_output_count":0,"warning_group_count":0,"warning_occurrence_count":0,"diagnostic_group_count":0,"diagnostic_occurrence_count":0,"diagnostics_truncated":false,"validation_status":"approved"}`, bundle))
|
||||
default:
|
||||
os.Exit(2)
|
||||
}
|
||||
_, _ = os.Stderr.WriteString(sharedProviderKey + "\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
Reference in New Issue
Block a user