Add additional subprocess diagnostics for the audita interface

This commit is contained in:
2026-05-04 13:05:04 -05:00
parent 4a593f9dcb
commit 15037c6d80
4 changed files with 102 additions and 3 deletions

View File

@@ -276,9 +276,27 @@ func buildDiagnostics(req RunRequest, result RunResult, stderrTail string) strin
req.StderrLogPath,
)
if strings.TrimSpace(stderrTail) == "" {
if hint := fdDiagnosticsHint(result.ExitCode, ""); hint != "" {
return details + fmt.Sprintf(" hint=%q", hint)
}
return details
}
return details + fmt.Sprintf(" stderr_tail=%q", stderrTail)
details = details + fmt.Sprintf(" stderr_tail=%q", stderrTail)
if hint := fdDiagnosticsHint(result.ExitCode, stderrTail); hint != "" {
details = details + fmt.Sprintf(" hint=%q", hint)
}
return details
}
func fdDiagnosticsHint(exitCode int, stderrTail string) string {
lowerTail := strings.ToLower(stderrTail)
if strings.Contains(lowerTail, "bad file descriptor") || strings.Contains(lowerTail, "errno 9") {
return "stderr stream appears invalid in child process (fd 2); check wrapper/subprocess environment differences versus direct shell execution"
}
if exitCode == 120 {
return "exit code 120 may indicate interpreter shutdown stream-flush failures (commonly invalid stdout/stderr descriptors in Python processes)"
}
return ""
}
func readRedactedTail(path string, envOverrides map[string]string, maxBytes int64) string {

View File

@@ -122,6 +122,35 @@ func TestRunFailureRedactsSensitiveTail(t *testing.T) {
}
}
func TestRunFailureAddsBadDescriptorHint(t *testing.T) {
exe, err := os.Executable()
if err != nil {
t.Fatalf("os.Executable() error = %v", err)
}
dir := t.TempDir()
req := RunRequest{
Executable: exe,
Args: []string{"-test.run=TestSubprocessHelper", "--", "failbadfd"},
EnvOverrides: map[string]string{
"GO_WANT_SUBPROCESS_HELPER": "1",
},
StdoutLogPath: filepath.Join(dir, "stdout.log"),
StderrLogPath: filepath.Join(dir, "stderr.log"),
}
_, err = Run(context.Background(), req)
if err == nil {
t.Fatal("Run() error = nil, want non-nil")
}
if !strings.Contains(err.Error(), "Bad file descriptor") {
t.Fatalf("error = %q, want stderr tail content", err.Error())
}
if !strings.Contains(err.Error(), "stderr stream appears invalid in child process") {
t.Fatalf("error = %q, want bad-descriptor hint", err.Error())
}
}
func TestRunTimeout(t *testing.T) {
exe, err := os.Executable()
if err != nil {
@@ -329,6 +358,9 @@ func TestSubprocessHelper(t *testing.T) {
key := os.Getenv("SUBPROCESS_HELPER_ENV_KEY")
_, _ = os.Stderr.WriteString("secret:" + os.Getenv(key) + "\n")
os.Exit(4)
case "failbadfd":
_, _ = os.Stderr.WriteString("OSError: [Errno 9] Bad file descriptor\n")
os.Exit(120)
case "sleep":
time.Sleep(500 * time.Millisecond)
os.Exit(0)