Resolve typed credentials safely

This commit is contained in:
2026-09-07 04:29:00 +00:00
parent d31ba5a410
commit 92432232ef
34 changed files with 572 additions and 260 deletions

View File

@@ -1,6 +1,7 @@
package config
import (
"encoding/json"
"io/fs"
"os"
"path/filepath"
@@ -8,6 +9,8 @@ import (
"sort"
"strings"
"testing"
"gopkg.in/yaml.v3"
)
func TestRepresentativeLoadDefaultsAndValidation(t *testing.T) {
@@ -83,6 +86,78 @@ whisperx:
}
}
func TestCredentialValuesNeverEnterEffectiveProjectionOrDigest(t *testing.T) {
const firstCanary = "credential-canary-first"
const secondCanary = "credential-canary-second"
t.Setenv("NARRATIO_TEST_ACCESS_KEY", firstCanary)
t.Setenv("NARRATIO_TEST_SECRET_KEY", firstCanary)
t.Setenv("NARRATIO_TEST_AUDITA_KEY", firstCanary)
pipelineYAML := strings.Replace(testPipelineBaseYAML, "audita:\n binary: audita\n", "audita:\n binary: audita\n llm_api_key: NARRATIO_TEST_AUDITA_KEY\n", 1) + `
storage:
backend: s3
s3:
bucket: test-bucket
access_key_id: NARRATIO_TEST_ACCESS_KEY
secret_access_key: NARRATIO_TEST_SECRET_KEY
`
pipelinePath, _ := writeConfigFiles(t, pipelineYAML, testSessionBaseYAML)
first, err := LoadPipeline(pipelinePath)
if err != nil {
t.Fatal(err)
}
firstYAML, err := MarshalEffectivePipeline(first)
if err != nil {
t.Fatal(err)
}
firstValues, err := EffectivePipelineValues(first)
if err != nil {
t.Fatal(err)
}
serializedValues := ""
for _, value := range firstValues {
serializedValues += value.Path + "=" + value.Value + "\n"
}
directYAML, err := yaml.Marshal(first)
if err != nil {
t.Fatal(err)
}
directJSON, err := json.Marshal(first)
if err != nil {
t.Fatal(err)
}
for _, output := range []string{string(firstYAML), serializedValues, string(directYAML), string(directJSON)} {
if strings.Contains(output, firstCanary) {
t.Fatalf("effective output exposed credential value: %q", output)
}
for _, reference := range []string{"NARRATIO_TEST_ACCESS_KEY", "NARRATIO_TEST_SECRET_KEY", "NARRATIO_TEST_AUDITA_KEY"} {
if !strings.Contains(output, reference) {
t.Fatalf("effective output omitted safe reference %q: %q", reference, output)
}
}
}
t.Setenv("NARRATIO_TEST_ACCESS_KEY", secondCanary)
t.Setenv("NARRATIO_TEST_SECRET_KEY", secondCanary)
t.Setenv("NARRATIO_TEST_AUDITA_KEY", secondCanary)
second, err := LoadPipeline(pipelinePath)
if err != nil {
t.Fatal(err)
}
if EffectivePipelineDigest(first) != EffectivePipelineDigest(second) {
t.Fatal("credential value change altered effective digest")
}
t.Setenv("NARRATIO_TEST_AUDITA_KEY_ALTERNATE", secondCanary)
alternatePath, _ := writeConfigFiles(t, strings.Replace(pipelineYAML, "NARRATIO_TEST_AUDITA_KEY", "NARRATIO_TEST_AUDITA_KEY_ALTERNATE", 1), testSessionBaseYAML)
alternate, err := LoadPipeline(alternatePath)
if err != nil {
t.Fatal(err)
}
if EffectivePipelineDigest(first) == EffectivePipelineDigest(alternate) {
t.Fatal("credential reference-name change did not alter effective digest")
}
}
func TestEffectivePipelineValuesPreserveNilEmptyAndExactIntegers(t *testing.T) {
base := &PipelineConfig{Audita: AuditaConfig{Modules: nil}}
nilValues, err := EffectivePipelineValues(base)
@@ -106,6 +181,13 @@ func TestEffectivePipelineValuesPreserveNilEmptyAndExactIntegers(t *testing.T) {
if got := effectiveValueForTest(t, emptyValues, "scriptorium.artifacts.recap.vars.exact"); got != "9007199254740993" {
t.Fatalf("exact integer value = %q", got)
}
encoded, err := MarshalEffectivePipeline(base)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(encoded), "9007199254740993") {
t.Fatalf("effective YAML lost exact integer: %q", encoded)
}
}
func effectiveValueForTest(t *testing.T, values []EffectivePipelineValueRecord, path string) string {
@@ -138,6 +220,9 @@ func TestValidateMissingAudioSource(t *testing.T) {
}
func TestExamplesLoadAndValidate(t *testing.T) {
t.Setenv("OBJECT_STORAGE_KEY_ID", "synthetic-example-access-key")
t.Setenv("OBJECT_STORAGE_KEY", "synthetic-example-secret-key")
t.Setenv("AUDITA_LLM_API_KEY", "synthetic-example-audita-key")
examplesDir := filepath.Join("..", "..", "examples")
if got, want := maintainedPipelineRoots(t, examplesDir), []string{
"pipeline.extraction-subset.yml",
@@ -226,7 +311,7 @@ func TestExamplesLoadAndValidate(t *testing.T) {
if cfg.Pipeline.Audita.Model != profile.model {
t.Fatalf("audita model = %q, want %q", cfg.Pipeline.Audita.Model, profile.model)
}
if cfg.Pipeline.Audita.LLMAPIKeyEnv != "" || cfg.Pipeline.Storage.Backend != StorageBackendLocal || cfg.Pipeline.Storage.S3 != nil {
if cfg.Pipeline.Audita.LLMAPIKey != nil || cfg.Pipeline.Storage.Backend != StorageBackendLocal || cfg.Pipeline.Storage.S3 != nil {
t.Fatalf("split bundle must remain offline and secret-free: audita=%#v storage=%#v", cfg.Pipeline.Audita, cfg.Pipeline.Storage)
}
if selectedProfile, ok := SelectedPipelineProfile(cfg.Pipeline); !ok || selectedProfile.Name != profile.name {
@@ -295,6 +380,9 @@ func maintainedPipelineRoots(t *testing.T, examplesDir string) []string {
}
func TestMaintainedExtractionExamplesPreservePublishedContracts(t *testing.T) {
t.Setenv("OBJECT_STORAGE_KEY_ID", "synthetic-example-access-key")
t.Setenv("OBJECT_STORAGE_KEY", "synthetic-example-secret-key")
t.Setenv("AUDITA_LLM_API_KEY", "synthetic-example-audita-key")
examplesDir := filepath.Join("..", "..", "examples")
full, err := LoadPipeline(filepath.Join(examplesDir, "pipeline.full.annotated.yml"))
if err != nil {