package launch import ( "errors" "os/exec" "os/user" "strings" "testing" ) // novox/hq ADR 0259 ยง8: a module naming an account of its own runs as it, never as root or the operator. func TestABundleRunsAsTheAccountItNamesAndNeverRootOrTheOperator(t *testing.T) { was := lookupUser t.Cleanup(func() { lookupUser = was }) lookupUser = func(name string) (*user.User, error) { switch name { case "telegram": return &user.User{Username: "telegram", Uid: "961", Gid: "961", HomeDir: "/var/lib/telegram"}, nil case "root": return &user.User{Username: "root", Uid: "0", Gid: "0", HomeDir: "/root"}, nil case "toor": return &user.User{Username: "toor", Uid: "0", Gid: "0", HomeDir: "/root"}, nil } return nil, errors.New("unknown user") } cmd := exec.Command("/bin/true") cmd.Env = []string{"HOME=/root", "PATH=/usr/bin"} if err := runAs(cmd, []string{RunAs + "=telegram", OperatorAccount + "=jo"}); err != nil { t.Fatal(err) } if c := cmd.SysProcAttr.Credential; c == nil || c.Uid != 961 || c.Gid != 961 { t.Fatalf("not started as telegram: %+v", cmd.SysProcAttr) } if env := strings.Join(cmd.Env, " "); !strings.Contains(env, "HOME=/var/lib/telegram") || strings.Contains(env, "HOME=/root") { t.Fatalf("the account's home is not its own: %s", env) } for name, want := range map[string]string{"jo": "operator's account", "root": "names root", "toor": "names root", "nobody-here": "does not have"} { err := runAs(exec.Command("/bin/true"), []string{RunAs + "=" + name, OperatorAccount + "=jo"}) if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("%s: %v, want a refusal saying %q", name, err, want) } } plain := exec.Command("/bin/true") if err := runAs(plain, nil); err != nil || plain.SysProcAttr != nil { t.Error("a bundle naming no account was changed") } }