Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 55 additions & 13 deletions actions/run_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ package actions

import (
"errors"
"github.com/go-debos/fakemachine"
"fmt"
"os"
"path"
"strings"

"github.com/go-debos/debos"
"github.com/go-debos/fakemachine"
)

const (
Expand All @@ -63,14 +65,54 @@ type RunAction struct {
Label string
}

func (run *RunAction) Verify(_ *debos.Context) error {
// extractScriptArgs returns the path to the script, relative to the recipe directory
// and its arguments as an array.
//
// Note: this function assumes there are no spaces in the script path itself, only
// a space between the path and arguments.
func (run *RunAction) extractScriptArgs(script string, recipeDir string) (string, []string) {
args := strings.Split(script, " ")
scriptPath := debos.CleanPathAt(args[0], recipeDir)
return scriptPath, args[1:]
}

func (run *RunAction) Verify(context *debos.Context) error {
if run.PostProcess && run.Chroot {
return errors.New("cannot run postprocessing in the chroot")
}

if run.Script == "" && run.Command == "" {
return errors.New("need to set 'script' or 'command'")
}

if run.Script != "" {
scriptPath, _ := run.extractScriptArgs(run.Script, context.RecipeDir)

/* Check the script exists on the filesystem (following symlinks) */
stat, err := os.Stat(scriptPath)
if err != nil {
return err
}

mode := stat.Mode()

if !mode.IsRegular() {
return fmt.Errorf("script %s is not a regular file or valid symlink", scriptPath)
}

/* Check the script is readable */
f, err := os.Open(scriptPath)
if err != nil {
return fmt.Errorf("script %s is not readable: %w", scriptPath, err)
}
f.Close()

/* Check the script is executable */
if mode&0111 == 0 {
return fmt.Errorf("script %s is not executable", scriptPath)
}
}

return nil
}

Expand All @@ -80,12 +122,10 @@ func (run *RunAction) PreMachine(context *debos.Context, m *fakemachine.Machine,
return nil
}

run.Script = debos.CleanPathAt(run.Script, context.RecipeDir)
// Expect we have no blank spaces in path
scriptpath := strings.Split(run.Script, " ")
scriptPath, _ := run.extractScriptArgs(run.Script, context.RecipeDir)

if !run.PostProcess {
m.AddVolume(path.Dir(scriptpath[0]))
m.AddVolume(path.Dir(scriptPath))
}

return nil
Expand All @@ -103,14 +143,16 @@ func (run *RunAction) doRun(context debos.Context) error {
}

if run.Script != "" {
script := strings.SplitN(run.Script, " ", 2)
script[0] = debos.CleanPathAt(script[0], context.RecipeDir)
scriptPath, scriptArgs := run.extractScriptArgs(run.Script, context.RecipeDir)

if run.Chroot {
scriptpath := path.Dir(script[0])
cmd.AddBindMount(scriptpath, "/tmp/script")
script[0] = strings.Replace(script[0], scriptpath, "/tmp/script", 1)
scriptDir := path.Dir(scriptPath)
cmd.AddBindMount(scriptDir, "/tmp/script")
scriptPath = strings.Replace(scriptPath, scriptDir, "/tmp/script", 1)
}
cmdline = []string{strings.Join(script, " ")}

cmdline = []string{scriptPath}
cmdline = append(cmdline, scriptArgs...)
label = path.Base(run.Script)
} else {
cmdline = []string{run.Command}
Expand Down Expand Up @@ -138,7 +180,7 @@ func (run *RunAction) doRun(context debos.Context) error {
}

// Command/script with options passed as single string
cmdline = append([]string{"sh", "-e", "-c"}, cmdline...)
cmdline = append([]string{"sh", "-e", "-c"}, strings.Join(cmdline, " "))

if !run.Chroot {
cmd.AddEnvKey("RECIPEDIR", context.RecipeDir)
Expand Down
4 changes: 4 additions & 0 deletions tests/exit_test/exit_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ expect_failure debos bad.yaml
expect_failure debos pre-machine-failure.yaml
expect_failure debos post-machine-failure.yaml
expect_failure debos overlay-non-existent-destination.yaml
expect_failure debos run-broken-symlink.yaml
expect_failure debos run-missing-script.yaml
expect_failure debos run-no-exec.yaml
expect_success debos run.yaml
expect_failure rename_command NOT_DEBOS debos good.yaml

expect_failure $SUDO debos non-existent-file.yaml --disable-fakemachine
Expand Down
7 changes: 7 additions & 0 deletions tests/exit_test/run-broken-symlink.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
architecture: amd64

actions:
- action: run
description: Run a script with broken symlink
chroot: true
script: run/scripts/broken-symlink.sh
7 changes: 7 additions & 0 deletions tests/exit_test/run-missing-script.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
architecture: amd64

actions:
- action: run
description: Run a script which doesn't exist
chroot: true
script: run/scripts/missing-script.sh
7 changes: 7 additions & 0 deletions tests/exit_test/run-no-exec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
architecture: amd64

actions:
- action: run
description: Run script with no exec bit set
chroot: true
script: run/scripts/no-exec.sh
38 changes: 38 additions & 0 deletions tests/exit_test/run.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
architecture: amd64

actions:
- action: debootstrap
suite: trixie
variant: minbase
merged-usr: true

- action: run
description: Run a script with arguments
script: run/scripts/test.sh argument1 argument2

- action: run
description: Run a script without arguments
script: run/scripts/test.sh

- action: run
description: Run a script with arguments in a chroot
chroot: true
script: run/scripts/test.sh argument1 argument2

- action: run
description: Run a script without arguments in chroot
chroot: true
script: run/scripts/test.sh

- action: run
description: Run a script which is a symlink
script: run/scripts/symlink-test.sh argument1 argument2

- action: run
description: Run a script which is a symlink in chroot
chroot: true
script: run/scripts/symlink-test.sh argument1 argument2

- action: run
description: Test running a command
command: echo test
1 change: 1 addition & 0 deletions tests/exit_test/run/scripts/broken-symlink.sh
Empty file.
1 change: 1 addition & 0 deletions tests/exit_test/run/scripts/symlink-test.sh
3 changes: 3 additions & 0 deletions tests/exit_test/run/scripts/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

echo "test from script; arguments: $@"