Complete facade inspection and secrets bootstrap
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
package configkit_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit/internal/facade"
|
||||
@@ -29,6 +33,10 @@ func TestFacadeValuesRemainRootOwned(t *testing.T) {
|
||||
reflect.TypeFor[configkit.FilesystemContext](), reflect.TypeFor[configkit.Override](),
|
||||
reflect.TypeFor[configkit.Definition[struct{}]](), reflect.TypeFor[configkit.Options[struct{}]](),
|
||||
reflect.TypeFor[configkit.Result[struct{}]](),
|
||||
reflect.TypeFor[configkit.ValueSnapshot](), reflect.TypeFor[configkit.ValueChange](),
|
||||
reflect.TypeFor[configkit.SecretReferenceInfo](), reflect.TypeFor[configkit.Explanation](),
|
||||
reflect.TypeFor[configkit.SecretFileResult](), reflect.TypeFor[configkit.SecretsReport](),
|
||||
reflect.TypeFor[configkit.SecretsError](),
|
||||
} {
|
||||
if candidate.PkgPath() != packagePath {
|
||||
t.Fatalf("type %s belongs to %q", candidate, candidate.PkgPath())
|
||||
@@ -48,6 +56,118 @@ func TestFacadeValuesRemainRootOwned(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFacadeInspectionUsesFrozenState(t *testing.T) {
|
||||
t.Setenv("FACADE_INSPECTION_SECRET", "credential")
|
||||
|
||||
type configuration struct {
|
||||
Value string `yaml:"value"`
|
||||
Secret configkit.Secret `yaml:"secret"`
|
||||
}
|
||||
result, err := configkit.Load[configuration](configkit.Bytes("inspection.yml", []byte("value: original\nsecret: FACADE_INSPECTION_SECRET\n")))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !result.Config.Secret.IsResolved() || result.Config.Secret.Value() != "credential" {
|
||||
t.Fatalf("secret = %#v", result.Config.Secret)
|
||||
}
|
||||
explanation, ok := result.Explain(configkit.Keys("value"))
|
||||
if !ok || explanation.Effective.YAML != "original\n" {
|
||||
t.Fatalf("explanation = %#v, %v", explanation, ok)
|
||||
}
|
||||
explanation.Effective.YAML = "mutated\n"
|
||||
result.Config.Value = "mutated"
|
||||
var effective bytes.Buffer
|
||||
if err := result.WriteEffective(&effective); err != nil || !strings.Contains(effective.String(), "value: original\n") || strings.Contains(effective.String(), "credential") {
|
||||
t.Fatalf("effective = %q, %v", effective.String(), err)
|
||||
}
|
||||
again, ok := result.Explain(configkit.Keys("value"))
|
||||
if !ok || again.Effective.YAML != "original\n" {
|
||||
t.Fatalf("inspection changed = %#v, %v", again, ok)
|
||||
}
|
||||
secret, ok := result.Explain(configkit.Keys("secret"))
|
||||
if !ok || secret.SecretReference == nil || secret.SecretReference.Name != "FACADE_INSPECTION_SECRET" {
|
||||
t.Fatalf("secret explanation = %#v, %v", secret, ok)
|
||||
}
|
||||
var explanationOutput bytes.Buffer
|
||||
if err := result.WriteExplanation(&explanationOutput, configkit.Keys("value")); err != nil || !strings.Contains(explanationOutput.String(), `path: "/value"`) {
|
||||
t.Fatalf("explanation output = %q, %v", explanationOutput.String(), err)
|
||||
}
|
||||
|
||||
unknown := bytes.NewBufferString("unchanged")
|
||||
if err := result.WriteExplanation(unknown, configkit.Keys("unknown")); err == nil || unknown.String() != "unchanged" {
|
||||
t.Fatalf("unknown explanation = %q, %v", unknown.String(), err)
|
||||
}
|
||||
var nilResult *configkit.Result[configuration]
|
||||
if _, ok := nilResult.Explain(configkit.Keys("value")); ok {
|
||||
t.Fatal("nil result explained a path")
|
||||
}
|
||||
if err := nilResult.WriteEffective(io.Discard); err == nil {
|
||||
t.Fatal("nil result rendered effective configuration")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFacadeSecretsBootstrapUsesFacadeRecords(t *testing.T) {
|
||||
const (
|
||||
loadedName = "FACADE_BOOTSTRAP_LOADED"
|
||||
existingName = "FACADE_BOOTSTRAP_EXISTING"
|
||||
)
|
||||
restore := func(name string) {
|
||||
value, present := os.LookupEnv(name)
|
||||
t.Cleanup(func() {
|
||||
if present {
|
||||
_ = os.Setenv(name, value)
|
||||
} else {
|
||||
_ = os.Unsetenv(name)
|
||||
}
|
||||
})
|
||||
}
|
||||
restore(loadedName)
|
||||
restore(existingName)
|
||||
if err := os.Unsetenv(loadedName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Setenv(existingName, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
directory := t.TempDir()
|
||||
if err := os.WriteFile(directory+"/"+loadedName, []byte("bootstrap\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(directory+"/"+existingName, []byte("ignored\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
report, err := configkit.LoadSecretsDir(directory)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entries := report.Entries()
|
||||
if len(entries) != 2 || os.Getenv(loadedName) != "bootstrap" {
|
||||
t.Fatalf("entries/environment = %#v / %q", entries, os.Getenv(loadedName))
|
||||
}
|
||||
status := map[string]configkit.SecretFileResult{}
|
||||
for _, entry := range entries {
|
||||
status[entry.Name] = entry
|
||||
}
|
||||
if status[loadedName].Status != configkit.SecretFileLoaded || status[existingName].Status != configkit.SecretFileSkippedExisting || !status[existingName].ExistingEmpty {
|
||||
t.Fatalf("statuses = %#v", status)
|
||||
}
|
||||
entries[0].Name = "mutated"
|
||||
if report.Entries()[0].Name == "mutated" {
|
||||
t.Fatal("report entries share mutable state")
|
||||
}
|
||||
var rendered bytes.Buffer
|
||||
if _, err := report.WriteTo(&rendered); err != nil || strings.Contains(rendered.String(), "bootstrap") || strings.Contains(rendered.String(), "ignored") {
|
||||
t.Fatalf("report rendering = %q, %v", rendered.String(), err)
|
||||
}
|
||||
|
||||
failedReport, err := configkit.LoadSecretsDir("")
|
||||
var secretsError *configkit.SecretsError
|
||||
if failedReport == nil || !errors.As(err, &secretsError) || len(secretsError.Diagnostics()) != 1 || secretsError.Diagnostics()[0].Code != configkit.CodeSecretsInvalidPath {
|
||||
t.Fatalf("bootstrap failure = %#v / %#v", failedReport, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFacadeLoadBridgesLifecycleCallbacks(t *testing.T) {
|
||||
t.Setenv("FACADE_SECRET_NAME", "credential")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user