Configuration Hardening
Key changes:
- Added internal/project/effective.go with normalized effective config, defaults, provenance, and
JSON output.
- Added config subcommands:
- config validate
- config effective [--json|--yaml]
- config inspect [<key>]
- config explain <key>
- config sources
- Added YAML schema fields for configurable outputs, cache roots, script cache, inventory extensions,
topdata output/wiki paths, and autogen cache root.
- Routed existing hardcoded paths through effective config wrappers for module archives, HAK
manifests/archives, script cache, music cache/credits, topdata outputs, and autogen caches.
- Added validation for unsafe generated output/cache paths.
- Updated command descriptions to avoid fixed build/, .cache, sow_top, etc.
- Added regression tests for defaults, provenance, deterministic effective config, YAML-controlled
derivation, config commands, and invalid paths.
This commit is contained in:
@@ -167,6 +167,9 @@ func buildModule(p *project.Project, progress ProgressFunc) (BuildResult, error)
|
||||
|
||||
progressf(progress, "Writing module archive...")
|
||||
outputPath := p.ModuleArchivePath()
|
||||
if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
|
||||
return BuildResult{}, fmt.Errorf("create module output dir: %w", err)
|
||||
}
|
||||
output, err := os.Create(outputPath)
|
||||
if err != nil {
|
||||
return BuildResult{}, fmt.Errorf("create module archive: %w", err)
|
||||
@@ -321,6 +324,9 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
return BuildResult{}, err
|
||||
}
|
||||
progressf(progress, "Writing HAK manifest...")
|
||||
if err := os.MkdirAll(filepath.Dir(manifestPath), 0o755); err != nil {
|
||||
return BuildResult{}, fmt.Errorf("create hak manifest dir: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(manifestPath, manifestBytes, 0o644); err != nil {
|
||||
return BuildResult{}, fmt.Errorf("write hak manifest: %w", err)
|
||||
}
|
||||
@@ -345,6 +351,9 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
} else {
|
||||
result.HAKSummary.Written++
|
||||
progressf(progress, fmt.Sprintf("Writing HAK %d/%d: %s (%d assets)", index+1, len(chunks), chunk.Name, len(chunk.Assets)))
|
||||
if err := os.MkdirAll(filepath.Dir(hakPath), 0o755); err != nil {
|
||||
return BuildResult{}, fmt.Errorf("create hak archive dir: %w", err)
|
||||
}
|
||||
hakOutput, err := os.Create(hakPath)
|
||||
if err != nil {
|
||||
return BuildResult{}, fmt.Errorf("create hak archive: %w", err)
|
||||
@@ -374,6 +383,9 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
}
|
||||
|
||||
progressf(progress, "Writing HAK manifest...")
|
||||
if err := os.MkdirAll(filepath.Dir(manifestPath), 0o755); err != nil {
|
||||
return BuildResult{}, fmt.Errorf("create hak manifest dir: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(manifestPath, manifestBytes, 0o644); err != nil {
|
||||
return BuildResult{}, fmt.Errorf("write hak manifest: %w", err)
|
||||
}
|
||||
@@ -558,7 +570,7 @@ func compileReferencedScripts(p *project.Project) ([]erf.Resource, error) {
|
||||
}
|
||||
|
||||
resources := make([]erf.Resource, 0, len(referenced))
|
||||
scriptsDir := filepath.Join(p.SourceDir(), "scripts")
|
||||
scriptsDir := p.ScriptSourceDir()
|
||||
for _, resref := range referenced {
|
||||
sourcePath, ok := scriptSources[resref]
|
||||
if !ok {
|
||||
@@ -586,7 +598,7 @@ func compileReferencedScripts(p *project.Project) ([]erf.Resource, error) {
|
||||
}
|
||||
|
||||
func compiledScriptCacheDir(p *project.Project) string {
|
||||
return filepath.Join(p.Root, ".cache", "ncs")
|
||||
return p.ScriptCacheDir()
|
||||
}
|
||||
|
||||
func referencedScriptResrefs(p *project.Project) ([]string, error) {
|
||||
|
||||
@@ -128,7 +128,7 @@ func prepareMusicAssets(p *project.Project) (*preparedMusicAssets, error) {
|
||||
sort.Strings(dirs)
|
||||
|
||||
generatedByDir := make(map[string][]creditsEntry)
|
||||
stageRoot := filepath.Join(p.Root, ".cache", "music")
|
||||
stageRoot := p.MusicStageDir()
|
||||
result.TempRoots = append(result.TempRoots, stageRoot)
|
||||
|
||||
ffmpegPath, err := resolveFFmpegBinary()
|
||||
@@ -144,7 +144,7 @@ func prepareMusicAssets(p *project.Project) (*preparedMusicAssets, error) {
|
||||
sources := append([]string(nil), dirSources[dir]...)
|
||||
sort.Strings(sources)
|
||||
prefix := musicPrefixForDir(p, dir)
|
||||
overlayPath := filepath.Join(p.AssetsDir(), filepath.FromSlash(dir), "CREDITS.md")
|
||||
overlayPath := filepath.Join(p.AssetsDir(), filepath.FromSlash(dir), p.EffectiveConfig().Music.CreditsOverlay)
|
||||
overlay, err := parseCreditsOverlay(overlayPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse credits overlay %s: %w", overlayPath, err)
|
||||
@@ -239,7 +239,7 @@ type creditsArtifactWriteResult struct {
|
||||
}
|
||||
|
||||
func writeCreditsArtifacts(p *project.Project, generatedByDir map[string][]creditsEntry) (creditsArtifactWriteResult, error) {
|
||||
creditsRoot := filepath.Join(p.Root, ".cache", "credits")
|
||||
creditsRoot := p.CreditsDir()
|
||||
sources := make([]creditsSource, 0)
|
||||
desiredFiles := make(map[string][]byte)
|
||||
summary := CreditsRefreshSummary{}
|
||||
@@ -260,7 +260,7 @@ func writeCreditsArtifacts(p *project.Project, generatedByDir map[string][]credi
|
||||
}
|
||||
return strings.ToLower(entries[i].OutputFile) < strings.ToLower(entries[j].OutputFile)
|
||||
})
|
||||
outputPath := filepath.Join(creditsRoot, filepath.FromSlash(dir), "CREDITS.md")
|
||||
outputPath := filepath.Join(creditsRoot, filepath.FromSlash(dir), p.EffectiveConfig().Music.CreditsOverlay)
|
||||
desiredFiles[outputPath] = []byte(renderCreditsMarkdown(entries))
|
||||
summary.GeneratedPaths = append(summary.GeneratedPaths, outputPath)
|
||||
for _, entry := range entries {
|
||||
|
||||
Reference in New Issue
Block a user