runExecCommand spawns the child per prep, feeds prep.Request on stdin, and returns trimmed stdout on success. Failure modes: - timeout → typed error with the configured limit - non-zero exit → wrapped *exec.ExitError - stdout exceeds prep.MaxOut → typed error (size enforced post-Run) - empty trimmed
(prep *execRun)
| 164 | // - stdout exceeds prep.MaxOut → typed error (size enforced post-Run) |
| 165 | // - empty trimmed stdout → typed error |
| 166 | func runExecCommand(prep *execRun) ([]byte, error) { |
| 167 | ctx, cancel := context.WithTimeout(context.Background(), prep.Timeout) |
| 168 | defer cancel() |
| 169 | |
| 170 | cmd := exec.CommandContext(ctx, prep.Path, prep.Args...) |
| 171 | cmd.Dir = filepath.Dir(prep.Path) |
| 172 | cmd.Env = prep.Env // always set — leaving nil would inherit the parent env |
| 173 | cmd.Stdin = bytes.NewReader(prep.Request) |
| 174 | |
| 175 | var stdout, stderr bytes.Buffer |
| 176 | cmd.Stdout = &stdout |
| 177 | cmd.Stderr = &stderr |
| 178 | |
| 179 | if err := cmd.Run(); err != nil { |
| 180 | if ctx.Err() == context.DeadlineExceeded { |
| 181 | return nil, fmt.Errorf("exec provider timed out after %dms", int(prep.Timeout/time.Millisecond)) |
| 182 | } |
| 183 | return nil, fmt.Errorf("exec provider exited with error: %w", err) |
| 184 | } |
| 185 | |
| 186 | if stdout.Len() > prep.MaxOut { |
| 187 | return nil, fmt.Errorf("exec provider output exceeded maxOutputBytes (%d)", prep.MaxOut) |
| 188 | } |
| 189 | |
| 190 | trimmed := bytes.TrimSpace(stdout.Bytes()) |
| 191 | if len(trimmed) == 0 { |
| 192 | return nil, fmt.Errorf("exec provider returned empty stdout") |
| 193 | } |
| 194 | return trimmed, nil |
| 195 | } |
| 196 | |
| 197 | // extractExecSecret parses stdout as a JSON execResponse and returns the |
| 198 | // string value at refID. When jsonOnly is false and the response is not valid |
no test coverage detected