diff --git a/commits.go b/commits.go index e85c976..3a7d8d0 100644 --- a/commits.go +++ b/commits.go @@ -96,14 +96,16 @@ func intersectKeys(ref map[string]bool, keys []string) []string { return ret } -func findCmdConfig(cmdName string, w *worker) (*commandCfg, bool) { +func findCmdConfig(cmdName string, w *worker) (commandCfg, bool) { + + var cmdNull commandCfg for _, c := range w.Commands { if c.Name == cmdName { - return &c, true + return c, true } } - return nil, false + return cmdNull, false } func getAuthorEmail(c *git.Commit) string { @@ -124,6 +126,7 @@ func getCommitterEmail(c *git.Commit) string { func walkCommits(msg spoolMsg, w *worker) error { var cmdMsg *clientMsg + var cmdStack = make([]command, 0) debug.log("[worker: %s] Inside walkCommits\n", w.Name) @@ -166,23 +169,26 @@ func walkCommits(msg spoolMsg, w *worker) error { // if it can be verified by any of the keyrings associated with // that specific scorsh-command - // Check if the commit contains a scorsh command + // Check if the commit contains a scorsh message cmdMsg, err = findScorshMessage(commit) if err == nil { // the commit contains a valid scorsh message - // 1) get the list of all the keyrings which verify the message + // 1) get the list of all the keyrings which verify the message signature validKeys := getValidKeys(commit, &(w.Keys)) debug.log("[worker: %s] validated keyrings on commit: %s\n", w.Name, validKeys) // 2) then for each command in the message for _, c := range cmdMsg.Commands { if c.Cmd == "" { + // The command is empty -- ignore, log, and continue log.Printf("[worker: %s] empty command\n", w.Name) continue } // a) check that the command is among those accepted by the worker debug.log("[worker: %s] validating command: %s\n", w.Name, c.Cmd) - cmdCfg, goodCmd := findCmdConfig(c.Cmd, w) + var cmd = new(command) + var goodCmd, goodKeys bool + cmd.commandCfg, goodCmd = findCmdConfig(c.Cmd, w) debug.log("[worker: %s] goodCmd: %s\n", w.Name, goodCmd) if !goodCmd { @@ -192,7 +198,7 @@ func walkCommits(msg spoolMsg, w *worker) error { // b) check that at least one of the accepted command keyrings // is in valid_keys - goodKeys := intersectKeys(w.CommandKeys[c.Cmd], validKeys) != nil + goodKeys = intersectKeys(w.CommandKeys[c.Cmd], validKeys) != nil debug.log("[worker: %s] goodKeys: %s\n", w.Name, goodKeys) if !goodKeys { @@ -200,11 +206,11 @@ func walkCommits(msg spoolMsg, w *worker) error { continue } - // c) If everything is OK, execute the command + // c) If everything is OK, push the command to the stack if goodCmd && goodKeys { - env := setEnvironment(&msg, c.Cmd, getAuthorEmail(commit), getCommitterEmail(commit)) - errs := execCommand(cmdCfg, c.Args, env) - debug.log("[worker: %s] errors in command %s: %s\n", w.Name, c.Cmd, errs) + cmd.setEnvironment(&msg, curCommit.Id().String(), getAuthorEmail(commit), getCommitterEmail(commit)) + cmd.Args = c.Args + cmdStack = append(cmdStack, *cmd) } } } else { @@ -216,6 +222,18 @@ func walkCommits(msg spoolMsg, w *worker) error { fmt.Printf("Commit %x not found!\n", curCommit.Id()) return SCORSHerr(errNoCommit) } + } + + stackHead := len(cmdStack) - 1 + debug.log("[worker: %s] Executing command stack:\n", w.Name) + for i := range cmdStack { + //debug.log("[stack elem: %d] %s\n", i, cmdStack[stackHead-i].String()) + // now we execute the command that emerges from the stack + cmd := cmdStack[stackHead-i] + errs := cmd.exec() + debug.log("[worker: %s] errors in command %s: %s\n", w.Name, cmd.Name, errs) + } + return nil } diff --git a/examples/worker1/worker1.cfg b/examples/worker1/worker1.cfg index f9a97f4..4fd0acc 100644 --- a/examples/worker1/worker1.cfg +++ b/examples/worker1/worker1.cfg @@ -15,7 +15,7 @@ w_commands: c_keyrings: ["allowed_users.asc"], c_actions: [ { - a_url: "file:///home/katolaz/bin/scorsh_script.sh" + a_url: "file:///home/katolaz/bin/scorsh_script_log.sh" ## a_hash: "12da324fb76s924acbce" } ] @@ -26,10 +26,19 @@ w_commands: c_actions: [ { a_url: "file:///home/katolaz/bin/scorsh_script.sh", - a_hash: "aa606bc152824c1b650d7e71e2e92bb69a9b7c861c69cd439d17902488e5f76e" + a_hash: "c129d4a12998c44dfb9a9fd61ec3159bf29606e0f7280f28bbd98fc6f972fa27" } ] - } + }, + { + c_name: "preview", + c_keyrings: ["allowed_users.asc"], + c_actions: [ + { + a_url: "file:///home/katolaz/bin/scorsh_preview.sh" + } + ] + } ] ... \ No newline at end of file diff --git a/exec.go b/exec.go index be52bd6..857cd72 100644 --- a/exec.go +++ b/exec.go @@ -7,7 +7,6 @@ import ( "io/ioutil" "log" "net/url" - "os" "os/exec" ) @@ -55,7 +54,7 @@ func execURL(cmdURL *url.URL, args, env []string) error { return nil } -func execCommand(cmd *commandCfg, args []string, env []string) []error { +func (cmd *command) exec() []error { var ret []error @@ -78,29 +77,14 @@ func execCommand(cmd *commandCfg, args []string, env []string) []error { continue } else { // finally, the command can be executed - err = execLocalFile(actionURL, args, env) + err = execLocalFile(actionURL, cmd.Args, cmd.Env) } } else if actionURL.Scheme == "http" || actionURL.Scheme == "https" { - err = execURL(actionURL, args, env) + err = execURL(actionURL, cmd.Args, cmd.Env) } } ret = append(ret, err) } return ret } - -func setEnvironment(msg *spoolMsg, cmd, author, committer string) []string { - - env := os.Environ() - env = append(env, fmt.Sprintf("SCORSH_REPO=%s", msg.Repo)) - env = append(env, fmt.Sprintf("SCORSH_BRANCH=%s", msg.Branch)) - env = append(env, fmt.Sprintf("SCORSH_OLDREV=%s", msg.OldRev)) - env = append(env, fmt.Sprintf("SCORSH_NEWREV=%s", msg.NewRev)) - env = append(env, fmt.Sprintf("SCORSH_ID=%s", msg.ID)) - env = append(env, fmt.Sprintf("SCORSH_COMMAND=%s", cmd)) - env = append(env, fmt.Sprintf("SCORSH_AUTHOR=%s", author)) - env = append(env, fmt.Sprintf("SCORSH_COMMITTER=%s", committer)) - - return env -} diff --git a/types.go b/types.go index 795e82f..de81e65 100644 --- a/types.go +++ b/types.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "golang.org/x/crypto/openpgp" + "os" ) // error constants @@ -39,6 +40,16 @@ type commandCfg struct { Actions []action `yaml:"c_actions"` } +type commandState struct { + Env []string + Args []string +} + +type command struct { + commandCfg + commandState +} + // workerCfg represents the static configuration of a worker type workerCfg struct { Name string `yaml:"w_name"` @@ -157,3 +168,30 @@ func (msg *clientMsg) String() string { return buff.String() } + +func (cmd *command) setEnvironment(msg *spoolMsg, commitID, author, committer string) { + + env := os.Environ() + env = append(env, fmt.Sprintf("SCORSH_REPO=%s", msg.Repo)) + env = append(env, fmt.Sprintf("SCORSH_BRANCH=%s", msg.Branch)) + env = append(env, fmt.Sprintf("SCORSH_OLDREV=%s", msg.OldRev)) + env = append(env, fmt.Sprintf("SCORSH_NEWREV=%s", msg.NewRev)) + env = append(env, fmt.Sprintf("SCORSH_ID=%s", msg.ID)) + env = append(env, fmt.Sprintf("SCORSH_COMMIT=%s", commitID)) + env = append(env, fmt.Sprintf("SCORSH_COMMAND=%s", cmd.Name)) + env = append(env, fmt.Sprintf("SCORSH_AUTHOR=%s", author)) + env = append(env, fmt.Sprintf("SCORSH_COMMITTER=%s", committer)) + cmd.Env = env +} + +func (cmd *command) String() string { + + var buff bytes.Buffer + + fmt.Fprintf(&buff, "Name: %s\n", cmd.Name) + fmt.Fprintf(&buff, "Keyrings: %s\n", cmd.Keyrings) + fmt.Fprintf(&buff, "Actions: %s\n", cmd.Actions) + fmt.Fprintf(&buff, "Env: %s\n", cmd.Env) + fmt.Fprintf(&buff, "Args: %s\n", cmd.Args) + return buff.String() +}