dashboard / erock/git-pr / refactor: require user to create an account #111 rss

open · opened on 2026-02-23T18:28:22Z by erock
Help
checkout latest patchset:
ssh pr.pico.sh print pr-111 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print ps-X | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 111
add review to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add --review 111
accept PR:
ssh pr.pico.sh pr accept 111
close PR:
ssh pr.pico.sh pr close 111
Timeline Patchsets

Patchset ps-201

refactor: require user to create an account

Eric Bower
2026-02-23T16:40:18Z
cli.go
+34 -15
e2e_test.go
+6 -0
pr.go
+6 -6
Back to top
We have noticed that users are accidentally creating accounts because we automatically create an account for any operation.  So instead we are going to require a one-line remote cli command to register the account first we can help users figure out they are using the wrong pubkey.
+34 -15 cli.go link
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
diff --git a/cli.go b/cli.go
index 9cf5073..f8f3212 100644
--- a/cli.go
+++ b/cli.go
@@ -13,6 +13,10 @@ import (
 	"github.com/urfave/cli/v2"
 )
 
+func errNotExist(host, pubkey string) error {
+	return fmt.Errorf("User does not exist, run `ssh <username>@%s register` to create an account\nPubkey: %s", host, pubkey)
+}
+
 func NewTabWriter(out io.Writer) *tabwriter.Writer {
 	return tabwriter.NewWriter(out, 0, 0, 1, ' ', tabwriter.TabIndent)
 }
@@ -237,7 +241,7 @@ To get started, submit a new patch request:
 					pubkey := be.Pubkey(sesh.PublicKey())
 					user, err := pr.GetUserByPubkey(pubkey)
 					if err != nil {
-						return err
+						return errNotExist(be.Cfg.Host, pubkey)
 					}
 					isPubkey := cCtx.Bool("pubkey")
 					prID := cCtx.Int64("pr")
@@ -290,6 +294,21 @@ To get started, submit a new patch request:
 					return nil
 				},
 			},
+			{
+				Name:  "register",
+				Usage: "Create an account",
+				Args:  true,
+				Flags: []cli.Flag{},
+				Action: func(cCtx *cli.Context) error {
+					pubkey := be.Pubkey(sesh.PublicKey())
+					user, err := pr.RegisterUser(pubkey, userName)
+					if err != nil {
+						return err
+					}
+					wish.Printf(sesh, "User created successfully!\nUser: %s\nPubkey: %s\n", user.Name, pubkey)
+					return nil
+				},
+			},
 			{
 				Name:  "ps",
 				Usage: "Mange patchsets",
@@ -347,9 +366,9 @@ To get started, submit a new patch request:
 						Args:      true,
 						ArgsUsage: "[repoName]",
 						Action: func(cCtx *cli.Context) error {
-							user, err := pr.UpsertUser(pubkey, userName)
+							user, err := pr.GetUserByPubkey(pubkey)
 							if err != nil {
-								return err
+								return errNotExist(be.Cfg.Host, pubkey)
 							}
 
 							args := cCtx.Args()
@@ -528,9 +547,9 @@ To get started, submit a new patch request:
 						Args:      true,
 						ArgsUsage: "[repoName]",
 						Action: func(cCtx *cli.Context) error {
-							user, err := pr.UpsertUser(pubkey, userName)
+							user, err := pr.GetUserByPubkey(pubkey)
 							if err != nil {
-								return err
+								return errNotExist(be.Cfg.Host, pubkey)
 							}
 
 							args := cCtx.Args()
@@ -631,9 +650,9 @@ To get started, submit a new patch request:
 									return err
 								}
 
-								user, err := pr.UpsertUser(pubkey, userName)
+								user, err := pr.GetUserByPubkey(pubkey)
 								if err != nil {
-									return err
+									return errNotExist(be.Cfg.Host, pubkey)
 								}
 
 								repo, err := pr.GetRepoByID(prq.RepoID)
@@ -717,9 +736,9 @@ To get started, submit a new patch request:
 									return fmt.Errorf("PR has already been closed")
 								}
 
-								user, err := pr.UpsertUser(pubkey, userName)
+								user, err := pr.GetUserByPubkey(pubkey)
 								if err != nil {
-									return err
+									return errNotExist(be.Cfg.Host, pubkey)
 								}
 
 								err = pr.UpdatePatchRequestStatus(prID, user.ID, StatusClosed, cCtx.String("comment"))
@@ -782,9 +801,9 @@ To get started, submit a new patch request:
 								return fmt.Errorf("PR is already open")
 							}
 
-							user, err := pr.UpsertUser(pubkey, userName)
+							user, err := pr.GetUserByPubkey(pubkey)
 							if err != nil {
-								return err
+								return errNotExist(be.Cfg.Host, pubkey)
 							}
 
 							err = pr.UpdatePatchRequestStatus(prID, user.ID, StatusOpen, cCtx.String("comment"))
@@ -814,9 +833,9 @@ To get started, submit a new patch request:
 								return err
 							}
 
-							user, err := pr.UpsertUser(pubkey, userName)
+							user, err := pr.GetUserByPubkey(pubkey)
 							if err != nil {
-								return err
+								return errNotExist(be.Cfg.Host, pubkey)
 							}
 
 							repo, err := pr.GetRepoByID(prq.RepoID)
@@ -885,9 +904,9 @@ To get started, submit a new patch request:
 								return err
 							}
 
-							user, err := pr.UpsertUser(pubkey, userName)
+							user, err := pr.GetUserByPubkey(pubkey)
 							if err != nil {
-								return err
+								return errNotExist(be.Cfg.Host, pubkey)
 							}
 
 							isReview := cCtx.Bool("review")
+6 -0 e2e_test.go link
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
diff --git a/e2e_test.go b/e2e_test.go
index 3a567ec..69f4287 100644
--- a/e2e_test.go
+++ b/e2e_test.go
@@ -31,6 +31,9 @@ func testSingleTenantE2E(t *testing.T) {
 	// Hack to wait for startup
 	time.Sleep(time.Millisecond * 100)
 
+	suite.userKey.MustCmd(suite.patch, "register")
+	suite.adminKey.MustCmd(suite.patch, "register")
+
 	t.Log("User cannot create repo")
 	_, err := suite.userKey.Cmd(suite.patch, "pr create test")
 	if err == nil {
@@ -63,6 +66,9 @@ func testMultiTenantE2E(t *testing.T) {
 
 	time.Sleep(time.Millisecond * 100)
 
+	suite.userKey.MustCmd(suite.patch, "register")
+	suite.adminKey.MustCmd(suite.patch, "register")
+
 	t.Log("Admin should be able to create a repo")
 	suite.adminKey.MustCmd(nil, "repo create test")
 
+6 -6 pr.go link
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
diff --git a/pr.go b/pr.go
index 049a223..f505e11 100644
--- a/pr.go
+++ b/pr.go
@@ -31,7 +31,7 @@ type GitPatchRequest interface {
 	GetRepoByID(repoID int64) (*Repo, error)
 	GetRepoByName(user *User, repoName string) (*Repo, error)
 	CreateRepo(user *User, repoName string) (*Repo, error)
-	UpsertUser(pubkey, name string) (*User, error)
+	RegisterUser(pubkey, name string) (*User, error)
 	IsBanned(pubkey, ipAddress string) error
 	SubmitPatchRequest(repoID int64, userID int64, patchset io.Reader) (*PatchRequest, error)
 	SubmitPatchset(prID, userID int64, op PatchsetOp, patchset io.Reader) ([]*Patch, error)
@@ -194,16 +194,16 @@ func (pr PrCmd) createUser(pubkey, name string) (*User, error) {
 	return user, err
 }
 
-func (pr PrCmd) UpsertUser(pubkey, name string) (*User, error) {
+func (pr PrCmd) RegisterUser(pubkey, name string) (*User, error) {
 	sanName := strings.ToLower(name)
 	if pubkey == "" {
 		return nil, fmt.Errorf("must provide pubkey during upsert")
 	}
-	user, err := pr.GetUserByPubkey(pubkey)
-	if err != nil {
-		user, err = pr.createUser(pubkey, sanName)
+	_, err := pr.GetUserByPubkey(pubkey)
+	if err == nil {
+		return nil, fmt.Errorf("pubkey is already registered by another user")
 	}
-	return user, err
+	return pr.createUser(pubkey, sanName)
 }
 
 func (pr PrCmd) GetPatchsetsByPrID(prID int64) ([]*Patchset, error) {