Introduce ScriptRunner seam into executor#369
Merged
Conversation
Define ScriptRunner as a function type and ShellRunner as its OS-backed implementation, encapsulating all shell-exec logic (script prep, stdio wiring, work dir, env layering). NewExecutor now accepts a ScriptRunner instead of an io.Writer; runCmd and executeAfterScript delegate to it, removing all direct os/exec calls from the orchestrator. Adds ADR-0001 documenting the decision and its testability motivation. Closes #362
Contributor
Reviewer's GuideIntroduces a ScriptRunner abstraction as the seam between the executor orchestration and OS process spawning, moving shell/OS-specific logic into a new shellRunner implementation and updating executor construction and call sites accordingly, plus documenting the design via an ADR. Sequence diagram for command execution via ScriptRunnersequenceDiagram
actor User
participant CobraCmd as CobraCommand
participant Executor
participant ScriptRunner
participant ShellProc as shellRunner
User->>CobraCmd: Execute
CobraCmd->>CobraCmd: newSubcommand()
CobraCmd->>Executor: NewExecutor(conf, NewShellRunner(conf, out))
User->>CobraCmd: run project command
CobraCmd->>Executor: Execute(ctx)
Executor->>Executor: runCmd(ctx, cmd)
Executor->>ScriptRunner: runner(command, cmd.Script)
ScriptRunner->>ShellProc: run(command, cmdScript)
ShellProc->>ShellProc: exec.Command(...).Run()
ShellProc-->>Executor: error or nil
Executor-->>CobraCmd: error or nil
CobraCmd-->>User: CLI exit code
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Hey - I've found 1 security issue, 1 other issue, and left some high level feedback:
Security issues:
- Detected non-static command inside Command. Audit the input to 'exec.Command'. If unverified user data can reach this call site, this is a code injection vulnerability. A malicious actor can inject a malicious script to execute arbitrary code. (link)
General comments:
- The previous debug-level-2 behavior that logged the full command environment (
fmtEnv(osCmd.Env)) for both main andafterscripts has been dropped fromrunCmd/executeAfterScriptand not reintroduced inshellRunner; if that output is still desired, consider adding environment logging inshellRunner.run(guarded byenv.DebugLevel() > 1) to preserve the earlier behavior described in the ADR. - Now that environment construction and execution are encapsulated in
shellRunner, any future logging or behavior that depends on the derived env (e.g., for debugging or dry-run output) will require additional plumbing into the runner; you may want to plan a small interface or struct wrapper aroundScriptRunnerto make extending it (logging, metrics, tracing) easier than with a bare function type.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The previous debug-level-2 behavior that logged the full command environment (`fmtEnv(osCmd.Env)`) for both main and `after` scripts has been dropped from `runCmd`/`executeAfterScript` and not reintroduced in `shellRunner`; if that output is still desired, consider adding environment logging in `shellRunner.run` (guarded by `env.DebugLevel() > 1`) to preserve the earlier behavior described in the ADR.
- Now that environment construction and execution are encapsulated in `shellRunner`, any future logging or behavior that depends on the derived env (e.g., for debugging or dry-run output) will require additional plumbing into the runner; you may want to plan a small interface or struct wrapper around `ScriptRunner` to make extending it (logging, metrics, tracing) easier than with a bare function type.
## Individual Comments
### Comment 1
<location path="internal/executor/executor.go" line_range="251-252" />
<code_context>
- }
-
- if env.DebugLevel() == 1 {
+ if env.DebugLevel() >= 1 {
ctx.logger.Debug("executing script:\n%s", cmd.Script)
- } else if env.DebugLevel() > 1 {
- ctx.logger.Debug("executing:\nscript: %s\nenv: %s\n", cmd.Script, fmtEnv(osCmd.Env))
</code_context>
<issue_to_address>
**question (bug_risk):** The change to `env.DebugLevel() >= 1` removes the more detailed env logging for higher debug levels.
Previously `DebugLevel()==1` logged only the script, while `DebugLevel()>1` also logged the resolved environment. With `>= 1` and no separate `> 1` branch, there’s no way to see the expanded env at higher debug levels, which can hinder diagnosing env-related issues. If this change wasn’t intentional, consider restoring a separate `DebugLevel() > 1` path (possibly delegating env logging elsewhere).
</issue_to_address>
### Comment 2
<location path="internal/executor/runner.go" line_range="39" />
<code_context>
osCmd := exec.Command(shell, args...)
</code_context>
<issue_to_address>
**security (go.lang.security.audit.dangerous-exec-command):** Detected non-static command inside Command. Audit the input to 'exec.Command'. If unverified user data can reach this call site, this is a code injection vulnerability. A malicious actor can inject a malicious script to execute arbitrary code.
*Source: opengrep*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ScriptRunnerasfunc(command *config.Command, script string) error— the seam between executor orchestration and OS process spawningShellRunner(NewShellRunner(cfg, out)) as the production implementation, encapsulating shell selection, script prep, stdio wiring, work dir resolution, and env layeringNewExecutornow accepts aScriptRunnerinstead ofio.Writer;runCmdandexecuteAfterScriptboth delegate to it, removing all directos/execcalls from the orchestratordocs/adr/0001-scriptrunner-seam.mddocumenting the decisionNo observable behaviour changes. All existing
go test ./...and Bats tests pass.Closes #362
Test plan
go test ./...— all packages passlets test-bats(Docker) for CLI path changesSummary by Sourcery
Introduce a ScriptRunner abstraction to decouple executor orchestration from OS process spawning and document the decision.
Enhancements:
Documentation: