Skip to content

Commit db864c5

Browse files
Fix ssh test preflight behaviors, and extract appropriate usernames from git ssh urls (#718)
fixes a few ux issues here
1 parent 737c50a commit db864c5

7 files changed

Lines changed: 109 additions & 30 deletions

File tree

cmd/command/up/up.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ func (p *Plural) handleUp(c *cli.Context) error {
120120
}
121121

122122
ctx, err := up.Build(c.Bool("cloud"))
123+
ctx.IgnorePreflights(c.Bool("ignore-preflights") || c.Bool("dry-run"))
123124
if err != nil {
124125
return err
125126
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ require (
5050
github.com/posthog/posthog-go v1.4.10
5151
github.com/samber/lo v1.52.0
5252
github.com/urfave/cli v1.22.16
53+
github.com/whilp/git-urls v1.0.0
5354
github.com/yuin/gopher-lua v1.1.1
5455
gitlab.com/gitlab-org/api/client-go v0.128.0
5556
golang.org/x/crypto v0.48.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,8 @@ github.com/vmihailenco/msgpack/v4 v4.3.13 h1:A2wsiTbvp63ilDaWmsk2wjx6xZdxQOvpiNl
740740
github.com/vmihailenco/msgpack/v4 v4.3.13/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
741741
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
742742
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
743+
github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU=
744+
github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE=
743745
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
744746
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
745747
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=

pkg/client/plural.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (p *Plural) HandleInitWithProject(c *cli.Context) (*manifest.ProjectManifes
111111
repo := ""
112112
p.InitPluralClient()
113113

114-
git, err := wkspace.Preflight(c.Bool("dry-run"))
114+
git, err := wkspace.Preflight(c.Bool("dry-run"), c.Bool("ignore-preflights"))
115115
if err != nil && (git || c.Bool("dry-run")) {
116116
return nil, err
117117
}

pkg/up/context.go

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"regexp"
78
"strings"
89

910
"github.com/AlecAivazis/survey/v2"
@@ -17,19 +18,21 @@ import (
1718
"github.com/pluralsh/plural-cli/pkg/utils/git"
1819

1920
"github.com/mitchellh/go-homedir"
21+
giturls "github.com/whilp/git-urls"
2022
)
2123

2224
type Context struct {
23-
Provider providerapi.Provider
24-
Manifest *manifest.ProjectManifest
25-
Config *config.Config
26-
Cloud bool
27-
RepoUrl string
28-
StacksIdentity string
29-
Delims *delims
30-
ImportCluster *string
31-
CloudCluster string
32-
dir string
25+
Provider providerapi.Provider
26+
Manifest *manifest.ProjectManifest
27+
Config *config.Config
28+
Cloud bool
29+
RepoUrl string
30+
StacksIdentity string
31+
Delims *delims
32+
ImportCluster *string
33+
CloudCluster string
34+
dir string
35+
ignorePreflights bool
3336
}
3437

3538
type delims struct {
@@ -50,23 +53,27 @@ func (ctx *Context) changeDelims() {
5053
ctx.Delims = &delims{"[[", "]]"}
5154
}
5255

56+
func (ctx *Context) IgnorePreflights(ignore bool) {
57+
ctx.ignorePreflights = ignore
58+
}
59+
5360
func (ctx *Context) SetImportCluster(id string) {
5461
ctx.ImportCluster = lo.ToPtr(id)
5562
}
5663

5764
func (ctx *Context) Backfill() error {
5865
context, err := manifest.FetchContext()
5966
if err != nil {
60-
return backfillConsoleContext(ctx.Manifest)
67+
return ctx.backfillConsoleContext(ctx.Manifest)
6168
}
6269

6370
console, ok := context.Configuration["console"]
6471
if !ok {
65-
return backfillConsoleContext(ctx.Manifest)
72+
return ctx.backfillConsoleContext(ctx.Manifest)
6673
}
6774

6875
if _, ok = console["private_key"]; !ok {
69-
return backfillConsoleContext(ctx.Manifest)
76+
return ctx.backfillConsoleContext(ctx.Manifest)
7077
}
7178

7279
if v, ok := console["repo_url"]; ok {
@@ -103,7 +110,7 @@ func Build(cloud bool) (*Context, error) {
103110
}, nil
104111
}
105112

106-
func backfillConsoleContext(_ *manifest.ProjectManifest) error {
113+
func (context *Context) backfillConsoleContext(_ *manifest.ProjectManifest) error {
107114
path := manifest.ContextPath()
108115
ctx, err := manifest.FetchContext()
109116
if err != nil {
@@ -115,7 +122,17 @@ func backfillConsoleContext(_ *manifest.ProjectManifest) error {
115122
console = map[string]interface{}{}
116123
}
117124

118-
utils.Highlight("It looks like you cloned this repo before running plural up, we just need you to generate and give us a deploy key to continue\n")
125+
utils.Highlight("It looks like you cloned this repo before running plural up, we just need to ensure authentication is setup correctly to continue\n")
126+
127+
url, err := git.GetURL()
128+
if err != nil {
129+
return err
130+
}
131+
132+
if strings.HasPrefix(url, "http") {
133+
return fmt.Errorf("found non-ssh upstream url %s, please reclone the repo with SSH and retry", url)
134+
}
135+
119136
utils.Highlight("If you want, you can use `plural crypto ssh-keygen` to generate a keypair to use as a deploy key as well\n\n")
120137

121138
files, err := filepath.Glob(filepath.Join(os.Getenv("HOME"), ".ssh", "*"))
@@ -144,17 +161,10 @@ func backfillConsoleContext(_ *manifest.ProjectManifest) error {
144161
return err
145162
}
146163

147-
url, err := git.GetURL()
148-
if err != nil {
149-
return err
150-
}
151-
152-
if strings.HasPrefix(url, "http") {
153-
return fmt.Errorf("found non-ssh upstream url %s, please reclone the repo with SSH and retry", url)
154-
}
155-
156-
if err := verifySSHKey(contents, url); err != nil {
157-
return fmt.Errorf("ssh key not valid for url %s, error: %w", url, err)
164+
if !context.ignorePreflights {
165+
if err := verifySSHKey(contents, url); err != nil {
166+
return fmt.Errorf("ssh key not valid for url %s, error: %w. If you want to bypass this check, you can use the --ignore-preflights flag", url, err)
167+
}
158168
}
159169

160170
console["repo_url"] = url
@@ -174,9 +184,30 @@ func verifySSHKey(key, url string) error {
174184
return
175185
}
176186
}(dir)
177-
auth, _ := git.SSHAuth("git", key, "")
187+
188+
auth, _ := git.SSHAuth(getGitUsername(url), key, "")
178189
if _, err := git.Clone(auth, url, dir); err != nil {
179190
return err
180191
}
181192
return nil
182193
}
194+
195+
var (
196+
scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9-._~]+@)?([a-zA-Z0-9._-]+):([a-zA-Z0-9./._-]+)(?:\?||$)(.*)$`)
197+
)
198+
199+
func getGitUsername(url string) string {
200+
match := scpSyntax.FindAllStringSubmatch(url, -1)
201+
if len(match) > 0 {
202+
if match[0][1] != "" {
203+
return strings.TrimRight(match[0][1], "@")
204+
}
205+
}
206+
207+
uname := "git"
208+
parsedUrl, err := giturls.Parse(url)
209+
if err == nil {
210+
uname = parsedUrl.User.Username()
211+
}
212+
return uname
213+
}

pkg/up/context_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package up
2+
3+
import "testing"
4+
5+
func TestGetGitUsername(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
url string
9+
want string
10+
}{
11+
{
12+
name: "github scp-style",
13+
url: "git@github.com:acme-corp/widget-service.git",
14+
want: "git",
15+
},
16+
{
17+
name: "github ssh transport",
18+
url: "ssh://git@github.com/acme-corp/widget-service.git",
19+
want: "git",
20+
},
21+
{
22+
name: "gitlab nested group",
23+
url: "git@gitlab.com:engineering/platform/api-gateway.git",
24+
want: "git",
25+
},
26+
{
27+
name: "azure devops ssh (v3 path)",
28+
url: "my-org@ssh.dev.azure.com:v3/MyOrg/MyProject/MyRepo",
29+
want: "my-org",
30+
},
31+
{
32+
name: "bitbucket cloud workspace repo",
33+
url: "another-org@bitbucket.org:acme-workspace/mobile-app.git",
34+
want: "another-org",
35+
},
36+
}
37+
for _, tt := range tests {
38+
t.Run(tt.name, func(t *testing.T) {
39+
if got := getGitUsername(tt.url); got != tt.want {
40+
t.Errorf("getGitUsername(%q) = %q, want %q", tt.url, got, tt.want)
41+
}
42+
})
43+
}
44+
}

pkg/wkspace/validator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"github.com/pluralsh/plural-cli/pkg/utils/git"
1313
)
1414

15-
func Preflight(dryRun bool) (bool, error) {
15+
func Preflight(dryRun, ignorePreflights bool) (bool, error) {
1616
requirements := []string{"terraform", "git"}
1717
if dryRun {
1818
requirements = []string{"git"}
@@ -24,7 +24,7 @@ func Preflight(dryRun bool) (bool, error) {
2424
}
2525
}
2626

27-
if !dryRun {
27+
if !dryRun && !ignorePreflights {
2828
fmt.Print("\nTesting if git ssh is properly configured...")
2929
if err := checkGitSSH(); err != nil {
3030
fmt.Printf("%s\n\n", err.Error())

0 commit comments

Comments
 (0)