Luigit
repositories / bugabinga.net

bugabinga.net

personal infrastructure for bugabinga!

owned by admin

services/luci/internal/sshcmd/sshcmd.go

Raw
package sshcmd

import (
	"fmt"
	"strings"
)

func Parse(original string) ([]string, error) {
	original = strings.TrimSpace(original)
	if original == "" {
		return nil, fmt.Errorf("empty SSH command")
	}
	if strings.ContainsAny(original, ";&|`$<>") {
		return nil, fmt.Errorf("shell syntax rejected")
	}
	fields := strings.Fields(original)
	if fields[0] == "luci" || fields[0] == "ci" {
		fields = fields[1:]
	}
	if len(fields) == 0 {
		return nil, fmt.Errorf("missing Luci command")
	}
	if fields[0] == "help" {
		fields[0] = "docs"
	}
	if fields[0] == "runs" {
		fields = []string{"status", "--all"}
	}
	switch fields[0] {
	case "run":
		if len(fields) != 5 {
			return nil, fmt.Errorf("usage: run <repo> <job> --ref <ref>|--rev <rev>")
		}
		if fields[3] != "--ref" && fields[3] != "--rev" {
			return nil, fmt.Errorf("usage: run <repo> <job> --ref <ref>|--rev <rev>")
		}
		return fields, nil
	case "status":
		if len(fields) > 2 || len(fields) == 2 && fields[1] != "--all" {
			return nil, fmt.Errorf("usage: status [--all]")
		}
		return fields, nil
	case "repo":
		if len(fields) != 2 {
			return nil, fmt.Errorf("usage: repo <repo>")
		}
		return fields, nil
	case "show":
		if len(fields) > 2 {
			return nil, fmt.Errorf("usage: show [run-id|repo]")
		}
		return fields, nil
	case "watch":
		selectors := 0
		for i := 1; i < len(fields); i++ {
			switch fields[i] {
			case "--json", "--logs":
			case "--timeout":
				i++
				if i == len(fields) {
					return nil, fmt.Errorf("usage: watch [run-id|repo] [--json] [--logs] [--timeout 30m]")
				}
			default:
				if strings.HasPrefix(fields[i], "-") {
					return nil, fmt.Errorf("usage: watch [run-id|repo] [--json] [--logs] [--timeout 30m]")
				}
				selectors++
			}
		}
		if selectors > 1 {
			return nil, fmt.Errorf("usage: watch [run-id|repo] [--json] [--logs] [--timeout 30m]")
		}
		return fields, nil
	case "log":
		if len(fields) > 3 {
			return nil, fmt.Errorf("usage: log [run-id|repo] [<child-id or job>]")
		}
		return fields, nil
	case "artifact":
		if len(fields) > 3 {
			return nil, fmt.Errorf("usage: artifact [run-id|repo] [path]")
		}
		return fields, nil
	case "docs", "env-check":
		if len(fields) != 1 {
			return nil, fmt.Errorf("usage: %s", fields[0])
		}
		return fields, nil
	default:
		return nil, fmt.Errorf("command %q not allowed, see: ci docs", fields[0])
	}
}