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 --ref |--rev ") } if fields[3] != "--ref" && fields[3] != "--rev" { return nil, fmt.Errorf("usage: run --ref |--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 ") } 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] []") } 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]) } }