Skip to content

Commit

Permalink
feat(actions): Add the ability to specify inline exec scripts. (#308)
Browse files Browse the repository at this point in the history
Signed-off-by: Simar <simar@linux.com>
  • Loading branch information
simar7 committed Mar 3, 2022
1 parent d6ccefd commit af11188
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 17 deletions.
12 changes: 10 additions & 2 deletions cfg-actions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ routes:

- name: actions-route
input: contains(input.SigMetadata.ID, "TRC-2")
outputs: [my-exec, my-http-get, my-http-post]
outputs: [my-exec, my-exec-2, my-http-get, my-http-post]
template: raw-json

# Templates are used to format a message
Expand All @@ -33,7 +33,15 @@ outputs:
type: exec
enable: true
env: ["MY_ENV_VAR=foo_bar_baz", "MY_KEY=secret"] # Optional. Any environment variables to pass in
input-file: /tmp/exec-test.sh # Required. Specify the path to the script to run
input-file: /tmp/exec-test.sh # Specify the path to the script to run

- name: my-exec-2
type: exec
enable: true
env: ["MY_ENV_VAR=foo_bar_baz", "MY_KEY=secret"] # Optional. Any environment variables to pass in
exec-script: | # Specify the script to run
#!/bin/sh
echo "hello world"
- name: my-http-get
type: http
Expand Down
25 changes: 17 additions & 8 deletions outputs/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ import (
"log"
"os"
"os/exec"
"strings"

"github.com/aquasecurity/postee/v2/layout"
)

type execCmd = func(string, ...string) *exec.Cmd

type ExecClient struct {
ExecCmd execCmd
Name string
Env []string
InputFile string
Output []byte
ExecCmd execCmd
Name string
Env []string
InputFile string
ExecScript string
Output []byte
}

func (e *ExecClient) GetName() string {
Expand All @@ -34,9 +36,16 @@ func (e *ExecClient) Send(m map[string]string) error {
envVars = append(envVars, e.Env...)
envVars = append(envVars, fmt.Sprintf("POSTEE_EVENT=%s", m["description"]))

// Set Postee event to be available inside the execution shell
cmd := e.ExecCmd("/bin/sh", e.InputFile)
cmd.Env = append(cmd.Env, envVars...)
var cmd *exec.Cmd
if len(e.InputFile) > 0 {
cmd = e.ExecCmd("/bin/sh", e.InputFile)
cmd.Env = append(cmd.Env, envVars...)
}
if len(e.ExecScript) > 0 {
cmd = e.ExecCmd("/bin/sh")
cmd.Env = append(cmd.Env, envVars...)
cmd.Stdin = strings.NewReader(e.ExecScript)
}

var err error
if e.Output, err = cmd.CombinedOutput(); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions outputs/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ input foo env var

t.Run("sad path - exec fails", func(t *testing.T) {
ec := ExecClient{
ExecScript: `#!/bin/sh
echo "foo bar baz"`,
ExecCmd: fakeExecCmdFailure,
}
require.EqualError(t, ec.Send(map[string]string{
Expand Down
27 changes: 22 additions & 5 deletions router/builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,29 @@ func buildJiraOutput(sourceSettings *OutputSettings) *outputs.JiraAPI {
return jiraApi
}

func buildExecOutput(sourceSettings *OutputSettings) *outputs.ExecClient {
return &outputs.ExecClient{
Name: sourceSettings.Name,
Env: sourceSettings.Env,
InputFile: sourceSettings.InputFile,
func buildExecOutput(sourceSettings *OutputSettings) (*outputs.ExecClient, error) {
if len(sourceSettings.InputFile) <= 0 && len(sourceSettings.ExecScript) <= 0 {
return nil, fmt.Errorf("exec action requires either input-file or exec-script to be set")
}

if len(sourceSettings.InputFile) > 0 && len(sourceSettings.ExecScript) > 0 {
return nil, fmt.Errorf("exec action only takes either input-file or exec-script, not both")
}

ec := &outputs.ExecClient{
Name: sourceSettings.Name,
Env: sourceSettings.Env,
}

if len(sourceSettings.InputFile) > 0 {
ec.InputFile = sourceSettings.InputFile
}

if len(sourceSettings.ExecScript) > 0 {
ec.ExecScript = sourceSettings.ExecScript
}

return ec, nil
}

func buildHTTPOutput(sourceSettings *OutputSettings) (*outputs.HTTPClient, error) {
Expand Down
41 changes: 40 additions & 1 deletion router/initoutputs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ func TestBuildAndInitOtpt(t *testing.T) {
map[string]interface{}{}, true,
"<nil>",
},
{"Exec Action output",
{"Exec Action output, with input-file config",
OutputSettings{
Name: "my-exec-output",
Env: []string{"foo=bar"},
Expand All @@ -300,6 +300,45 @@ func TestBuildAndInitOtpt(t *testing.T) {
false,
"*outputs.ExecClient",
},
{"Exec Action output, with exec-script config",
OutputSettings{
Name: "my-exec-output",
Env: []string{"foo=bar"},
ExecScript: `#!/bin/sh
echo "foo bar"`,
Type: "exec",
},
map[string]interface{}{
"Name": "Exec Output",
"ExecScript": `#!/bin/sh
echo "foo bar"`,
},
false,
"*outputs.ExecClient",
},
{"Exec Action output, with invalid config (both file and script)",
OutputSettings{
Name: "my-exec-output",
Env: []string{"foo=bar"},
InputFile: "goldens/test.txt",
ExecScript: `#!/bin/sh
echo "foo bar"`,
Type: "exec",
},
map[string]interface{}{},
true,
"<nil>",
},
{"Exec Action output, with invalid config (no file nor script)",
OutputSettings{
Name: "my-exec-output",
Env: []string{"foo=bar"},
Type: "exec",
},
map[string]interface{}{},
true,
"<nil>",
},
}
for _, test := range tests {
o := BuildAndInitOtpt(&test.outputSettings, "")
Expand Down
1 change: 1 addition & 0 deletions router/integrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type OutputSettings struct {
InstanceName string `json:"instance,omitempty"`
SizeLimit int `json:"size-limit,omitempty"`
InputFile string `json:"input-file,omitempty"`
ExecScript string `json:"exec-script,omitempty"`
Env []string `json:"env,omitempty"`
BodyFile string `json:"bodyfile,omitempty"`
Method string `json:"method,omitempty"`
Expand Down
6 changes: 5 additions & 1 deletion router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,11 @@ func BuildAndInitOtpt(settings *OutputSettings, aquaServerUrl string) outputs.Ou
case "stdout":
plg = buildStdoutOutput(settings)
case "exec":
plg = buildExecOutput(settings)
plg, err = buildExecOutput(settings)
if err != nil {
log.Println(err.Error())
return nil
}
case "http":
plg, err = buildHTTPOutput(settings)
if err != nil {
Expand Down

0 comments on commit af11188

Please sign in to comment.