Fail a bare invocation when stdout is not a terminal
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/integration Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline failed

Puppet's generate() reads stdout through a pipe with combine: true, so help
text on a zero exit lands in the catalog. Help now requires an interactive
stdout; a piped one exits non-zero with nothing on stdout.

- gate the no-args help path on an isTerminal(stdout) check
- reject an explicitly empty --config instead of resolving it
- ignore a relative XDG_CONFIG_HOME, per the XDG spec
- give the integration subprocess a hermetic HOME/XDG_CONFIG_HOME
- pass []string{} to run(), so cobra cannot fall back to os.Args
This commit is contained in:
2026-09-22 22:50:05 +10:00
parent f7c8ca5fba
commit 4ff55f052a
7 changed files with 219 additions and 22 deletions
+4 -2
View File
@@ -40,7 +40,8 @@ func FallbackPath() string { return defaultPath }
// are only taken when the file is actually there, so an unset or unusable
// HOME lands on the Puppet-managed path instead of a path that cannot exist.
func DefaultPath() string {
if base := os.Getenv("XDG_CONFIG_HOME"); base != "" {
// The XDG spec requires a relative XDG_CONFIG_HOME to be ignored.
if base := os.Getenv("XDG_CONFIG_HOME"); filepath.IsAbs(base) {
if p := filepath.Join(base, "certmanager", "config.yaml"); isFile(p) {
return p
}
@@ -53,7 +54,8 @@ func DefaultPath() string {
return defaultPath
}
// Resolve picks the config path for a run: an explicit --config always wins.
// Resolve picks the config path for a run: a non-empty explicit --config
// always wins, an empty one means "resolve".
func Resolve(explicit string) string {
if explicit != "" {
return explicit
+17 -3
View File
@@ -204,7 +204,7 @@ func TestDefaultPathIgnoresADirectory(t *testing.T) {
func TestResolvePrefersExplicitPath(t *testing.T) {
xdg := t.TempDir()
seedConfig(t, xdg)
resolved := seedConfig(t, xdg)
t.Setenv("XDG_CONFIG_HOME", xdg)
t.Setenv("HOME", t.TempDir())
@@ -212,8 +212,22 @@ func TestResolvePrefersExplicitPath(t *testing.T) {
if got := Resolve(explicit); got != explicit {
t.Errorf("Resolve(%q) = %q, want the explicit path", explicit, got)
}
if got := Resolve(""); got == explicit {
t.Error("Resolve(\"\") returned the explicit path")
if got := Resolve(""); got != resolved {
t.Errorf("Resolve(\"\") = %q, want the resolved path %q", got, resolved)
}
}
// The XDG spec says a non-absolute XDG_CONFIG_HOME must be ignored, so a
// config sitting under the working directory cannot be picked up.
func TestDefaultPathIgnoresRelativeXDG(t *testing.T) {
wd := t.TempDir()
seedConfig(t, filepath.Join(wd, "xdg"))
t.Chdir(wd)
t.Setenv("XDG_CONFIG_HOME", "xdg")
t.Setenv("HOME", t.TempDir())
if got := DefaultPath(); got != FallbackPath() {
t.Errorf("DefaultPath() = %q, want %q", got, FallbackPath())
}
}