Clarify search and secret bootstrap names
This commit is contained in:
@@ -52,8 +52,8 @@ func SearchDirectory(directory string, supplied ...DirectorySearchOptions) Searc
|
|||||||
return Search{value: engine.SearchDirectory(directory, options...)}
|
return Search{value: engine.SearchDirectory(directory, options...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paths describes literal host-file candidates in the supplied order.
|
// SearchPaths describes literal host-file candidates in the supplied order.
|
||||||
func Paths(paths ...string) Search { return Search{value: engine.Paths(paths...)} }
|
func SearchPaths(paths ...string) Search { return Search{value: engine.Paths(paths...)} }
|
||||||
|
|
||||||
// Searches concatenates descriptions in order and snapshots their entries.
|
// Searches concatenates descriptions in order and snapshots their entries.
|
||||||
func Searches(searches ...Search) Search {
|
func Searches(searches ...Search) Search {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Pre-v1 Public API Cleanup Implementation Plan
|
# Pre-v1 Public API Cleanup Implementation Plan
|
||||||
|
|
||||||
Status: in progress; Stages 1–4 are complete and Stages 5–11 are pending.
|
Status: in progress; Stages 1–5 are complete and Stages 6–11 are pending.
|
||||||
Baseline: `07e4ae5d9236935389e81b207d4a8f00543fafce`.
|
Baseline: `07e4ae5d9236935389e81b207d4a8f00543fafce`.
|
||||||
Audience: a Luna coding agent executing the stages sequentially.
|
Audience: a Luna coding agent executing the stages sequentially.
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ ordinary/layered loading.
|
|||||||
|
|
||||||
## Stage 5 — Clarify Discovery And Environment Bootstrap Names
|
## Stage 5 — Clarify Discovery And Environment Bootstrap Names
|
||||||
|
|
||||||
Status: pending. Implements N1 and D7.
|
Status: complete. Implements N1 and D7.
|
||||||
|
|
||||||
1. In root [discovery.go](../../discovery.go), rename `Paths` to `SearchPaths`.
|
1. In root [discovery.go](../../discovery.go), rename `Paths` to `SearchPaths`.
|
||||||
Forward the same literal candidates to existing engine machinery. Migrate
|
Forward the same literal candidates to existing engine machinery. Migrate
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func Example_weatherStartup() {
|
|||||||
defer os.RemoveAll(directory)
|
defer os.RemoveAll(directory)
|
||||||
_ = os.WriteFile(filepath.Join(directory, blockedName), []byte("unused-example-value\n"), 0o600)
|
_ = os.WriteFile(filepath.Join(directory, blockedName), []byte("unused-example-value\n"), 0o600)
|
||||||
_ = os.WriteFile(filepath.Join(directory, tokenName), []byte("disposable-example-credential\n"), 0o600)
|
_ = os.WriteFile(filepath.Join(directory, tokenName), []byte("disposable-example-credential\n"), 0o600)
|
||||||
report, bootstrapErr := configkit.LoadSecretsDir(directory)
|
report, bootstrapErr := configkit.LoadSecretsIntoEnvironment(directory)
|
||||||
var reportOutput bytes.Buffer
|
var reportOutput bytes.Buffer
|
||||||
_, reportWriteErr := report.WriteTo(&reportOutput)
|
_, reportWriteErr := report.WriteTo(&reportOutput)
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func LoadSequenceCatalog(mainPath, overlayName, runLabel string) (*configkit.Res
|
|||||||
filesystem := configkit.NewFilesystem("sequence catalog", os.DirFS(root))
|
filesystem := configkit.NewFilesystem("sequence catalog", os.DirFS(root))
|
||||||
filesystemContext := &configkit.FilesystemContext{BaseDir: ".", Root: ".", FS: &filesystem}
|
filesystemContext := &configkit.FilesystemContext{BaseDir: ".", Root: ".", FS: &filesystem}
|
||||||
mainSearch := configkit.SearchConfig("", configkit.Searches(
|
mainSearch := configkit.SearchConfig("", configkit.Searches(
|
||||||
configkit.Paths(absoluteMain),
|
configkit.SearchPaths(absoluteMain),
|
||||||
configkit.SearchDirectory(filepath.Join(root, "fallback"), configkit.DirectorySearchOptions{
|
configkit.SearchDirectory(filepath.Join(root, "fallback"), configkit.DirectorySearchOptions{
|
||||||
Filenames: []configkit.FilenameGroup{configkit.CustomFilenames(filepath.Base(absoluteMain))},
|
Filenames: []configkit.FilenameGroup{configkit.CustomFilenames(filepath.Base(absoluteMain))},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func TestFacadeSecretsBootstrapUsesFacadeRecords(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
report, err := configkit.LoadSecretsDir(directory)
|
report, err := configkit.LoadSecretsIntoEnvironment(directory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ func TestFacadeSecretsBootstrapUsesFacadeRecords(t *testing.T) {
|
|||||||
t.Fatalf("report rendering = %q, %v", rendered.String(), err)
|
t.Fatalf("report rendering = %q, %v", rendered.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
failedReport, err := configkit.LoadSecretsDir("")
|
failedReport, err := configkit.LoadSecretsIntoEnvironment("")
|
||||||
var secretsError *configkit.SecretsError
|
var secretsError *configkit.SecretsError
|
||||||
if failedReport == nil || !errors.As(err, &secretsError) || len(secretsError.Diagnostics()) != 1 || secretsError.Diagnostics()[0].Code != configkit.CodeSecretsInvalidPath {
|
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)
|
t.Fatalf("bootstrap failure = %#v / %#v", failedReport, err)
|
||||||
|
|||||||
@@ -93,14 +93,14 @@ func TestFacadeSearchOrderingRequirednessAndSnapshots(t *testing.T) {
|
|||||||
names := []string{"config.yml"}
|
names := []string{"config.yml"}
|
||||||
groups := []FilenameGroup{CustomFilenames(names...)}
|
groups := []FilenameGroup{CustomFilenames(names...)}
|
||||||
directoryOptions := []DirectorySearchOptions{{Filenames: groups}}
|
directoryOptions := []DirectorySearchOptions{{Filenames: groups}}
|
||||||
search := Searches(Paths(paths...), SearchDirectory(root, directoryOptions...), Paths(laterPath))
|
search := Searches(SearchPaths(paths...), SearchDirectory(root, directoryOptions...), SearchPaths(laterPath))
|
||||||
source := SearchConfig("", search, SearchOptions{Required: true})
|
source := SearchConfig("", search, SearchOptions{Required: true})
|
||||||
|
|
||||||
paths[0] = laterPath
|
paths[0] = laterPath
|
||||||
names[0] = "later.yml"
|
names[0] = "later.yml"
|
||||||
groups[0] = CustomFilenames("later.yml")
|
groups[0] = CustomFilenames("later.yml")
|
||||||
directoryOptions[0].Filenames[0] = CustomFilenames("later.yml")
|
directoryOptions[0].Filenames[0] = CustomFilenames("later.yml")
|
||||||
search = Paths(laterPath)
|
search = SearchPaths(laterPath)
|
||||||
|
|
||||||
result, err := Load[facadeDiscoveryConfig](source)
|
result, err := Load[facadeDiscoveryConfig](source)
|
||||||
if err != nil || result.Config.Value != "selected" {
|
if err != nil || result.Config.Value != "selected" {
|
||||||
@@ -110,7 +110,7 @@ func TestFacadeSearchOrderingRequirednessAndSnapshots(t *testing.T) {
|
|||||||
t.Fatalf("ordered search sources = %#v", sources)
|
t.Fatalf("ordered search sources = %#v", sources)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = Load[facadeDiscoveryConfig](SearchConfig("", Paths(filepath.Join(root, "missing.yml")), SearchOptions{Required: true}))
|
_, err = Load[facadeDiscoveryConfig](SearchConfig("", SearchPaths(filepath.Join(root, "missing.yml")), SearchOptions{Required: true}))
|
||||||
var loadErr *LoadError
|
var loadErr *LoadError
|
||||||
if !errors.As(err, &loadErr) {
|
if !errors.As(err, &loadErr) {
|
||||||
t.Fatalf("required exhausted search error = %v, want *LoadError", err)
|
t.Fatalf("required exhausted search error = %v, want *LoadError", err)
|
||||||
@@ -131,7 +131,7 @@ func TestFacadeSearchWorksForLayeredMainAndUnderlay(t *testing.T) {
|
|||||||
mainPath := writeFacadeImportFile(t, root, "main.yml", "settings: {main: value}\n")
|
mainPath := writeFacadeImportFile(t, root, "main.yml", "settings: {main: value}\n")
|
||||||
underlayPath := writeFacadeImportFile(t, root, "underlay/base.yml", "settings: {underlay: value}\n")
|
underlayPath := writeFacadeImportFile(t, root, "underlay/base.yml", "settings: {underlay: value}\n")
|
||||||
result, err := LoadLayered(
|
result, err := LoadLayered(
|
||||||
Input{Source: SearchConfig("", Paths(mainPath))},
|
Input{Source: SearchConfig("", SearchPaths(mainPath))},
|
||||||
LayeredOptions[facadeDiscoveryConfig]{Underlays: []Underlay{{Inputs: []Input{{
|
LayeredOptions[facadeDiscoveryConfig]{Underlays: []Underlay{{Inputs: []Input{{
|
||||||
Source: SearchConfig("", SearchDirectory(filepath.Dir(underlayPath), DirectorySearchOptions{
|
Source: SearchConfig("", SearchDirectory(filepath.Dir(underlayPath), DirectorySearchOptions{
|
||||||
Filenames: []FilenameGroup{CustomFilenames("base.yml")},
|
Filenames: []FilenameGroup{CustomFilenames("base.yml")},
|
||||||
@@ -157,7 +157,7 @@ func TestFacadeSearchSelectedAndAbsentUseRootOnlyContext(t *testing.T) {
|
|||||||
filesystem := &FilesystemContext{Root: root}
|
filesystem := &FilesystemContext{Root: root}
|
||||||
options := Options[facadeDiscoveryConfig]{Overlay: "testing", Filesystem: filesystem}
|
options := Options[facadeDiscoveryConfig]{Overlay: "testing", Filesystem: filesystem}
|
||||||
|
|
||||||
selected, err := Load(SearchConfig("", Paths(mainPath)), options)
|
selected, err := Load(SearchConfig("", SearchPaths(mainPath)), options)
|
||||||
if err != nil || selected.Config.Value != "overlay" {
|
if err != nil || selected.Config.Value != "overlay" {
|
||||||
t.Fatalf("selected search with root-only context = %#v, %v", selected, err)
|
t.Fatalf("selected search with root-only context = %#v, %v", selected, err)
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ func TestFacadeSearchSelectedAndAbsentUseRootOnlyContext(t *testing.T) {
|
|||||||
t.Fatalf("selected file base context = %#v, %v", mainContext, ok)
|
t.Fatalf("selected file base context = %#v, %v", mainContext, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
missing := SearchConfig("", Paths(filepath.Join(root, "missing.yml")))
|
missing := SearchConfig("", SearchPaths(filepath.Join(root, "missing.yml")))
|
||||||
searchedAbsent, err := Load(missing, options)
|
searchedAbsent, err := Load(missing, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("exhausted search with root-only overlay context: %v", err)
|
t.Fatalf("exhausted search with root-only overlay context: %v", err)
|
||||||
@@ -201,7 +201,7 @@ func TestFacadeSearchRejectsSelectedContextWithoutFallback(t *testing.T) {
|
|||||||
inside := writeFacadeImportFile(t, root, "inside.yml", "value: fallback\n")
|
inside := writeFacadeImportFile(t, root, "inside.yml", "value: fallback\n")
|
||||||
outsideRoot := t.TempDir()
|
outsideRoot := t.TempDir()
|
||||||
outside := writeFacadeImportFile(t, outsideRoot, "outside.yml", "value: selected\n")
|
outside := writeFacadeImportFile(t, outsideRoot, "outside.yml", "value: selected\n")
|
||||||
search := SearchConfig("", Paths(outside, inside))
|
search := SearchConfig("", SearchPaths(outside, inside))
|
||||||
|
|
||||||
_, err := Load(search, Options[facadeDiscoveryConfig]{Filesystem: &FilesystemContext{Root: root}})
|
_, err := Load(search, Options[facadeDiscoveryConfig]{Filesystem: &FilesystemContext{Root: root}})
|
||||||
var loadErr *LoadError
|
var loadErr *LoadError
|
||||||
@@ -228,7 +228,7 @@ func TestFacadeSearchRunsCallbacksOnceAndKeepsInspectionWithSelectedFile(t *test
|
|||||||
selectedPath := writeFacadeImportFile(t, root, "selected.yml", "value: selected\n")
|
selectedPath := writeFacadeImportFile(t, root, "selected.yml", "value: selected\n")
|
||||||
writeFacadeImportFile(t, root, "later.yml", "value: later\n")
|
writeFacadeImportFile(t, root, "later.yml", "value: later\n")
|
||||||
defaultsCalls, resolveCalls, validateCalls := 0, 0, 0
|
defaultsCalls, resolveCalls, validateCalls := 0, 0, 0
|
||||||
result, err := Load(SearchConfig("", Paths(selectedPath, filepath.Join(root, "later.yml"))), Options[facadeDiscoveryLifecycleConfig]{
|
result, err := Load(SearchConfig("", SearchPaths(selectedPath, filepath.Join(root, "later.yml"))), Options[facadeDiscoveryLifecycleConfig]{
|
||||||
Definition: Definition[facadeDiscoveryLifecycleConfig]{
|
Definition: Definition[facadeDiscoveryLifecycleConfig]{
|
||||||
Defaults: func() facadeDiscoveryLifecycleConfig {
|
Defaults: func() facadeDiscoveryLifecycleConfig {
|
||||||
defaultsCalls++
|
defaultsCalls++
|
||||||
@@ -272,7 +272,7 @@ func TestFacadeSearchSequenceItemAndAbsentInputPlacement(t *testing.T) {
|
|||||||
Destination: Keys("items"),
|
Destination: Keys("items"),
|
||||||
PlacementMode: PlacementModeSequenceItem,
|
PlacementMode: PlacementModeSequenceItem,
|
||||||
}
|
}
|
||||||
selected, err := Load(SearchConfig("", Paths(selectedPath)), options)
|
selected, err := Load(SearchConfig("", SearchPaths(selectedPath)), options)
|
||||||
if err != nil || len(selected.Config.Items) != 1 || selected.Config.Items[0].Name != "selected" {
|
if err != nil || len(selected.Config.Items) != 1 || selected.Config.Items[0].Name != "selected" {
|
||||||
t.Fatalf("selected sequence item = %#v, %v", selected, err)
|
t.Fatalf("selected sequence item = %#v, %v", selected, err)
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,7 @@ func TestFacadeSearchSequenceItemAndAbsentInputPlacement(t *testing.T) {
|
|||||||
defaults := func() facadeDiscoveryPlacementConfig {
|
defaults := func() facadeDiscoveryPlacementConfig {
|
||||||
return facadeDiscoveryPlacementConfig{Items: []facadeDiscoveryPlacementItem{}}
|
return facadeDiscoveryPlacementConfig{Items: []facadeDiscoveryPlacementItem{}}
|
||||||
}
|
}
|
||||||
absent, err := Load(SearchConfig("", Paths(filepath.Join(root, "missing.yml"))), Options[facadeDiscoveryPlacementConfig]{
|
absent, err := Load(SearchConfig("", SearchPaths(filepath.Join(root, "missing.yml"))), Options[facadeDiscoveryPlacementConfig]{
|
||||||
Definition: Definition[facadeDiscoveryPlacementConfig]{Defaults: defaults},
|
Definition: Definition[facadeDiscoveryPlacementConfig]{Defaults: defaults},
|
||||||
Destination: options.Destination,
|
Destination: options.Destination,
|
||||||
PlacementMode: options.PlacementMode,
|
PlacementMode: options.PlacementMode,
|
||||||
|
|||||||
13
secrets.go
13
secrets.go
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SecretFileStatus describes the outcome for one file considered by
|
// SecretFileStatus describes the outcome for one file considered by
|
||||||
// LoadSecretsDir.
|
// LoadSecretsIntoEnvironment.
|
||||||
type SecretFileStatus string
|
type SecretFileStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -85,11 +85,12 @@ func (e *SecretsError) Diagnostics() []Diagnostic {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadSecretsDir explicitly loads immediate regular files from directory into
|
// LoadSecretsIntoEnvironment explicitly loads immediate regular files into the
|
||||||
// previously unset process environment variables. Applications should call it
|
// process environment, preserving variables that are already set, including
|
||||||
// once during startup, before concurrent work; Load never calls it.
|
// empty values. Dot-prefixed entries are ignored and omitted from the report.
|
||||||
// Dot-prefixed entries are ignored and omitted from the report.
|
// Load never calls it. The report accompanies any error, and an error does not
|
||||||
func LoadSecretsDir(directory string) (*SecretsReport, error) {
|
// roll back values already applied.
|
||||||
|
func LoadSecretsIntoEnvironment(directory string) (*SecretsReport, error) {
|
||||||
report, err := engine.LoadSecretsDir(directory)
|
report, err := engine.LoadSecretsDir(directory)
|
||||||
result := &SecretsReport{value: report}
|
result := &SecretsReport{value: report}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user