From 4637026bc477a3f230399ebb9332b20e5884cac8 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Sun, 4 Oct 2026 13:21:13 +0000 Subject: [PATCH] Test a config file that links to itself and a HOME that is a file The test for a directory pixa may not enter is skipped as root, where the gate runs the tests. A config.yml in the working directory that is a symbolic link to itself fails os.Stat as root too, and must abort startup. A config path that runs through a file, such as one under a HOME of /dev/null, cannot hold a file and must be passed over like one that does not exist; today it aborts startup. Model: opus-5-5 --- .../config/config_validation_internal_test.go | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/internal/config/config_validation_internal_test.go b/internal/config/config_validation_internal_test.go index 8399aba..1800ab3 100644 --- a/internal/config/config_validation_internal_test.go +++ b/internal/config/config_validation_internal_test.go @@ -618,6 +618,62 @@ func TestConfigFileInDirectoryPixaMayNotEnterAbortsStartup(t *testing.T) { } } +// TestConfigFileLinkingToItselfAbortsStartup checks that a config file +// pixa cannot read for a reason other than not existing aborts startup, +// as root too: a symbolic link to itself fails with "too many levels of +// symbolic links". +func TestConfigFileLinkingToItselfAbortsStartup(t *testing.T) { + workDir := t.TempDir() + + err := os.Symlink("config.yml", filepath.Join(workDir, "config.yml")) + if err != nil { + t.Fatalf("failed to create symbolic link: %v", err) + } + + // Only the working directory's config.yml is there: the appname rules + // out /etc, and HOME is empty. + t.Setenv("PIXA_CONFIG_PATH", "") + t.Setenv("HOME", t.TempDir()) + t.Chdir(workDir) + + log := slog.New(slog.DiscardHandler) + + sc, err := loadConfigFile(log, "pixa-test-nonexistent-app") + if err == nil { + t.Fatalf("config file pixa cannot read must abort startup, got config: %v", + sc) + } + + t.Logf("got expected error: %v", err) + + if !strings.Contains(err.Error(), "config.yml") { + t.Errorf("error %q does not name the config file config.yml", err.Error()) + } +} + +// TestConfigPathThroughFileIsPassedOver checks that a config file path +// that runs through a file, such as one under a HOME of /dev/null, is +// passed over like one that does not exist, since no file can be there. +func TestConfigPathThroughFileIsPassedOver(t *testing.T) { + // No config file is there: the appname rules out /etc, HOME is + // /dev/null, and the working directory is empty. + t.Setenv("PIXA_CONFIG_PATH", "") + t.Setenv("HOME", os.DevNull) + t.Chdir(t.TempDir()) + + log := slog.New(slog.DiscardHandler) + + sc, err := loadConfigFile(log, "pixa-test-nonexistent-app") + if err != nil { + t.Fatalf("a config path through a file must be passed over, got error: %v", + err) + } + + if sc != nil { + t.Errorf("expected no config file, got config: %v", sc) + } +} + func TestEnsureStateDirCreatesDirectory(t *testing.T) { t.Parallel()