feat(14-01): sunscreen redacting slog handler installed by every generated main

- Wrap redacts sensitive keys at any depth and scrubs Bearer, sk- and x-api-key shapes
- InstallDefault is the first statement of the generated run; hello main regenerated
- surf test pins that recovered panics echo no credential
- sunscreen README, root modules row and the logging docs page
This commit is contained in:
Jakub Zych
2026-10-03 20:01:36 +02:00
parent ee0004fb65
commit 7241704e93
11 changed files with 591 additions and 1 deletions

View File

@@ -93,6 +93,7 @@ func generateMain(m Manifest) ([]byte, error) {
b.WriteString("\t\"git.golem15.com/golem15/summercms/modules/lagoon\"\n")
b.WriteString("\t\"git.golem15.com/golem15/summercms/modules/pact\"\n")
b.WriteString("\t\"git.golem15.com/golem15/summercms/modules/party\"\n")
b.WriteString("\t\"git.golem15.com/golem15/summercms/modules/sunscreen\"\n")
b.WriteString("\t\"git.golem15.com/golem15/summercms/modules/surf\"\n")
b.WriteString(")\n\n")
b.WriteString("func main() {\n")
@@ -102,6 +103,7 @@ func generateMain(m Manifest) ([]byte, error) {
b.WriteString("\t}\n")
b.WriteString("}\n\n")
b.WriteString("func run(args []string, out io.Writer) error {\n")
b.WriteString("\tsunscreen.InstallDefault(os.Stderr)\n")
b.WriteString("\tcfg, err := compass.Load(\"config\")\n")
b.WriteString("\tif err != nil {\n")
b.WriteString("\t\treturn err\n")

View File

@@ -142,6 +142,32 @@ func TestGenerateMainRegistersCongaRuntimeCommands(t *testing.T) {
}
}
// TestGenerateMainInstallsRedactingLogger: the first statement of run makes
// the credential-redacting handler the default logger, before config loads
// or any plugin can log.
func TestGenerateMainInstallsRedactingLogger(t *testing.T) {
mainSrc, err := generateMain(Manifest{Module: "example.com/app", Binary: "hello"})
if err != nil {
t.Fatal(err)
}
line := []byte("sunscreen.InstallDefault(os.Stderr)")
if n := bytes.Count(mainSrc, line); n != 1 {
t.Fatalf("InstallDefault count = %d, want 1\n%s", n, mainSrc)
}
if !bytes.Contains(mainSrc, []byte(`"git.golem15.com/golem15/summercms/modules/sunscreen"`)) {
t.Fatalf("generated main does not import sunscreen:\n%s", mainSrc)
}
install := bytes.Index(mainSrc, line)
runStart := bytes.Index(mainSrc, []byte("func run(args []string, out io.Writer) error {"))
load := bytes.Index(mainSrc, []byte("compass.Load("))
if runStart < 0 || load < 0 || !(runStart < install && install < load) {
t.Fatalf("InstallDefault must be the first statement of run, before compass.Load:\n%s", mainSrc)
}
if between := bytes.TrimSpace(mainSrc[runStart+len("func run(args []string, out io.Writer) error {") : install]); len(between) != 0 {
t.Fatalf("statements before InstallDefault: %q", between)
}
}
// TestGenerateMainPublishesCommandCatalog: the generated main publishes the
// final command list as a *bonfire.Catalog after collecting plugin commands
// and before building the root, so scheduled runs can call any command.