Report secrets bootstrap outcomes safely
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -99,9 +101,13 @@ func TestSecretsBootstrapPreservesExistingEnvironmentValues(t *testing.T) {
|
||||
}
|
||||
|
||||
bootstrap := &secretsBootstrap{selection: &directory, selectionSet: true}
|
||||
if err := bootstrap.load(filepath.Join(t.TempDir(), "pipeline.yml"), configkit.LoadSecretsDir); err != nil {
|
||||
var diagnostics bytes.Buffer
|
||||
if err := bootstrap.load(filepath.Join(t.TempDir(), "pipeline.yml"), configkit.LoadSecretsDir, &diagnostics); err != nil {
|
||||
t.Fatalf("bootstrap: %v", err)
|
||||
}
|
||||
if got := diagnostics.String(); !strings.Contains(got, `status="skipped_existing"`) || !strings.Contains(got, `existing_empty=true`) {
|
||||
t.Fatalf("diagnostics lack explicit skipped-empty result: %q", got)
|
||||
}
|
||||
if got := os.Getenv(emptyName); got != "" {
|
||||
t.Fatalf("existing empty value = %q, want empty", got)
|
||||
}
|
||||
@@ -117,7 +123,7 @@ 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)
|
||||
err := bootstrap.load(filepath.Join(t.TempDir(), "pipeline.yml"), configkit.LoadSecretsDir, io.Discard)
|
||||
if err == nil {
|
||||
t.Fatal("bootstrap succeeded, want error")
|
||||
}
|
||||
@@ -129,4 +135,66 @@ func TestSecretsBootstrapPreservesSafePartialReportOnFailure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteConfigShowReportsSuccessfulSecretsBootstrapOnStderr(t *testing.T) {
|
||||
workspaceRoot := t.TempDir()
|
||||
pipelinePath, _, _ := writeValidConfigFiles(t, workspaceRoot)
|
||||
secretsDir := t.TempDir()
|
||||
const name = "NARRATIO_BOOTSTRAP_REPORT_SECRET"
|
||||
const canary = "synthetic-secret-must-not-appear"
|
||||
restoreEnvAfterTest(t, name)
|
||||
if err := os.Unsetenv(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mustWriteSecretFile(t, filepath.Join(secretsDir, name), canary+"\n")
|
||||
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
if code := Execute([]string{"config", "show", "--config", pipelinePath, "--secrets-dir", secretsDir}, &stdout, &stderr); code != 0 {
|
||||
t.Fatalf("config show exit = %d, stderr = %q", code, stderr.String())
|
||||
}
|
||||
if got := stderr.String(); !strings.Contains(got, `status="loaded"`) || !strings.Contains(got, `name="`+name+`"`) {
|
||||
t.Fatalf("stderr lacks safe bootstrap report: %q", got)
|
||||
}
|
||||
if strings.Contains(stderr.String(), canary) || strings.Contains(stdout.String(), canary) {
|
||||
t.Fatal("command output exposed secret value")
|
||||
}
|
||||
if strings.Contains(stdout.String(), `status="loaded"`) || strings.Contains(stdout.String(), name) {
|
||||
t.Fatalf("show stdout was polluted by bootstrap report: %q", stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteConfigValidateReportsSkippedEmptyBeforeTypedLoadFailure(t *testing.T) {
|
||||
workspaceRoot := t.TempDir()
|
||||
pipelinePath, _, _ := writeValidConfigFiles(t, workspaceRoot)
|
||||
const name = "NARRATIO_REVIEW_KEY"
|
||||
const canary = "synthetic-skipped-secret-must-not-appear"
|
||||
t.Setenv(name, "")
|
||||
pipelineYAML, err := os.ReadFile(pipelinePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pipelineYAML = []byte(strings.Replace(string(pipelineYAML), "audita:\n binary:", "audita:\n llm_api_key: "+name+"\n binary:", 1))
|
||||
if err := os.WriteFile(pipelinePath, pipelineYAML, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
secretsDir := t.TempDir()
|
||||
mustWriteSecretFile(t, filepath.Join(secretsDir, name), canary+"\n")
|
||||
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
if code := Execute([]string{"config", "validate", "--config", pipelinePath, "--secrets-dir", secretsDir}, &stdout, &stderr); code == 0 {
|
||||
t.Fatal("config validate succeeded, want empty-secret failure")
|
||||
}
|
||||
got := stderr.String()
|
||||
if !strings.Contains(got, `status="skipped_existing"`) || !strings.Contains(got, `existing_empty=true`) {
|
||||
t.Fatalf("stderr lacks useful skipped-empty diagnostic: %q", got)
|
||||
}
|
||||
if !strings.Contains(got, "secret.empty") {
|
||||
t.Fatalf("stderr lacks typed load failure: %q", got)
|
||||
}
|
||||
if strings.Contains(got, canary) || strings.Contains(stdout.String(), canary) {
|
||||
t.Fatal("command output exposed skipped secret value")
|
||||
}
|
||||
}
|
||||
|
||||
func stringPointer(value string) *string { return &value }
|
||||
|
||||
Reference in New Issue
Block a user