Files
narratio/internal/app/secrets_bootstrap_test.go

133 lines
4.5 KiB
Go

package app
import (
"os"
"path/filepath"
"strings"
"testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
"gitea.maximumdirect.net/eric/narratio/internal/config"
)
func TestPipelineLoadSkipsAbsentConventionalSecretsDirectory(t *testing.T) {
pipelinePath := filepath.Join(t.TempDir(), "pipeline.yml")
if err := os.WriteFile(pipelinePath, []byte("version: 1\n"), 0o644); err != nil {
t.Fatal(err)
}
secretCalls := 0
pipelineCalls := 0
deps := commandDependencies{
loadSecretsDir: func(string) (*configkit.SecretsReport, error) {
secretCalls++
return nil, nil
},
loadPipelineConfig: func(string, config.PipelineLoadOptions) (*config.PipelineConfig, error) {
pipelineCalls++
return &config.PipelineConfig{}, nil
},
}
if _, _, err := loadPipelineConfigWithDependencies(pipelinePath, config.PipelineLoadOptions{}, nil, deps); err != nil {
t.Fatalf("load pipeline: %v", err)
}
if secretCalls != 0 || pipelineCalls != 1 {
t.Fatalf("calls = secrets %d, pipeline %d; want 0, 1", secretCalls, pipelineCalls)
}
}
func TestExplicitSecretsDirectoryIsResolvedFromCallerWorkingDirectory(t *testing.T) {
callerDir := t.TempDir()
selected := filepath.Join(callerDir, "credentials")
if err := os.Mkdir(selected, 0o700); err != nil {
t.Fatal(err)
}
original, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
if err := os.Chdir(callerDir); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = os.Chdir(original) })
got, required, err := selectedSecretsDirectory(filepath.Join(t.TempDir(), "pipeline.yml"), stringPointer("credentials"))
if err != nil {
t.Fatalf("select secrets: %v", err)
}
if !required || got != selected {
t.Fatalf("selection = %q, required=%t; want %q, true", got, required, selected)
}
}
func TestExplicitSecretsFailurePrecedesPipelineLoad(t *testing.T) {
pipelinePath := filepath.Join(t.TempDir(), "pipeline.yml")
if err := os.WriteFile(pipelinePath, []byte("version: 1\n"), 0o644); err != nil {
t.Fatal(err)
}
for name, selection := range map[string]string{"empty": "", "missing": filepath.Join(t.TempDir(), "missing")} {
t.Run(name, func(t *testing.T) {
pipelineCalls := 0
deps := commandDependencies{loadPipelineConfig: func(string, config.PipelineLoadOptions) (*config.PipelineConfig, error) {
pipelineCalls++
return &config.PipelineConfig{}, nil
}}
if _, _, err := loadPipelineConfigWithDependencies(pipelinePath, config.PipelineLoadOptions{}, &selection, deps); err == nil {
t.Fatal("load succeeded, want bootstrap error")
}
if pipelineCalls != 0 {
t.Fatalf("pipeline load calls = %d, want 0", pipelineCalls)
}
})
}
}
func TestSecretsBootstrapPreservesExistingEnvironmentValues(t *testing.T) {
directory := t.TempDir()
const emptyName = "NARRATIO_BOOTSTRAP_EXISTING_EMPTY"
const valueName = "NARRATIO_BOOTSTRAP_EXISTING_VALUE"
const loadedName = "NARRATIO_BOOTSTRAP_NEW_VALUE"
t.Setenv(emptyName, "")
t.Setenv(valueName, "from-environment")
restoreEnvAfterTest(t, loadedName)
for name, value := range map[string]string{
emptyName: "from-file-empty\n",
valueName: "from-file-value\n",
loadedName: "new-value\n",
} {
mustWriteSecretFile(t, filepath.Join(directory, name), value)
}
bootstrap := &secretsBootstrap{selection: &directory, selectionSet: true}
if err := bootstrap.load(filepath.Join(t.TempDir(), "pipeline.yml"), configkit.LoadSecretsDir); err != nil {
t.Fatalf("bootstrap: %v", err)
}
if got := os.Getenv(emptyName); got != "" {
t.Fatalf("existing empty value = %q, want empty", got)
}
if got := os.Getenv(valueName); got != "from-environment" {
t.Fatalf("existing value = %q, want environment value", got)
}
if got := os.Getenv(loadedName); got != "new-value" {
t.Fatalf("new value = %q, want file value", got)
}
}
func TestSecretsBootstrapPreservesSafePartialReportOnFailure(t *testing.T) {
directory := t.TempDir()
mustWriteSecretFile(t, filepath.Join(directory, "INVALID-NAME"), "must-not-appear\n")
bootstrap := &secretsBootstrap{selection: &directory, selectionSet: true}
err := bootstrap.load(filepath.Join(t.TempDir(), "pipeline.yml"), configkit.LoadSecretsDir)
if err == nil {
t.Fatal("bootstrap succeeded, want error")
}
if !strings.Contains(err.Error(), `status="failed"`) || !strings.Contains(err.Error(), `name="INVALID-NAME"`) {
t.Fatalf("error lacks partial report: %v", err)
}
if strings.Contains(err.Error(), "must-not-appear") {
t.Fatalf("error exposed secret value: %v", err)
}
}
func stringPointer(value string) *string { return &value }