Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

actions: run: Check script exists during recipe verification #302

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ jobs:
test: { name: "arch", case: "arch" }
- backend: kvm
test: { name: "apertis", case: "apertis" }
- backend: kvm
test: { name: "run", case: "run" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kvm actually has the highest latency atm because of the runner setup; and really this should probably run on all types.. That said could you merge it with an existing tests so we don't need a new CI job for it ?

e.g. maybe merge it with the recipes test and the overlay test :)

name: ${{matrix.test.name}} on ${{matrix.backend}}
runs-on: 'ubuntu-latest'
steps:
Expand Down
49 changes: 36 additions & 13 deletions actions/run_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ package actions
import (
"errors"
"github.com/go-debos/fakemachine"
"fmt"
"os"
"path"
"strings"

Expand All @@ -62,6 +64,9 @@ type RunAction struct {
Script string
Command string
Label string

scriptPath string
scriptArgs []string
}

func (run *RunAction) Verify(context *debos.DebosContext) error {
Expand All @@ -72,6 +77,29 @@ func (run *RunAction) Verify(context *debos.DebosContext) error {
if run.Script == "" && run.Command == "" {
return errors.New("Script and Command both cannot be empty")
}

if run.Script != "" {
/* Extract the full script path from the arguments */
args := strings.Split(run.Script, " ")
run.scriptPath = debos.CleanPathAt(args[0], context.RecipeDir)
run.scriptArgs = args[1:]

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

if stat.IsDir() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather then checking if it's a Dir this should proably check if it's a regular file

return fmt.Errorf("script %s is a directory", run.Script)
}

/* Check the script is executable */
if stat.Mode()&0111 == 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executable and readable ideally; though i don't think golang gives you nice helpers for that unfortunately :/

return fmt.Errorf("script %s is not executable", run.Script)
}
}

return nil
}

Expand All @@ -82,12 +110,8 @@ func (run *RunAction) PreMachine(context *debos.DebosContext, m *fakemachine.Mac
return nil
}

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

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

return nil
Expand All @@ -105,15 +129,14 @@ func (run *RunAction) doRun(context debos.DebosContext) error {
}

if run.Script != "" {
script := strings.SplitN(run.Script, " ", 2)
script[0] = debos.CleanPathAt(script[0], 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(run.scriptPath)
cmd.AddBindMount(scriptDir, "/tmp/script")
run.scriptPath = strings.Replace(run.scriptPath, scriptDir, "/tmp/script", 1)
}
cmdline = []string{strings.Join(script, " ")}
label = path.Base(run.Script)
cmdline = []string{run.scriptPath}
cmdline = append(cmdline, run.scriptArgs...)
label = path.Base(run.scriptPath)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but then you don't see the arguments to the script anymore, which is a loss.. Probably this doesn't belong in this PR (it doesn't help with your stated target i think) but preventing "pollution" we could do either by:

  • unify truncating the length like the Command handling does
  • printing what gets run first and then either not or only providing a minimal label on each line after

} else {
cmdline = []string{run.Command}

Expand All @@ -140,7 +163,7 @@ func (run *RunAction) doRun(context debos.DebosContext) error {
}

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

if !run.Chroot {
cmd.AddEnvKey("RECIPEDIR", context.RecipeDir)
Expand Down
1 change: 1 addition & 0 deletions tests/run/scripts/test-broken-symlink.sh
Empty file.
1 change: 1 addition & 0 deletions tests/run/scripts/test-symlink.sh
3 changes: 3 additions & 0 deletions tests/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: $@"
46 changes: 46 additions & 0 deletions tests/run/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
architecture: amd64

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

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

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

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

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

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

- action: run
description: Test running a command
command: echo test

# TODO: This should fail in the Verify stage, we cannot yet check that in CI
#- action: run
# description: Run a script which has a broken symlink
# chroot: true
# script: scripts/test-broken-symlink.sh

# TODO: This should fail in the Verify stage, we cannot yet check that in CI
#- action: run
# description: Run a script which has no exec bit set
# chroot: true
# script: scripts/test-broken-symlink.sh
Loading