diff --git a/cmd/flux/bootstrap.go b/cmd/flux/bootstrap.go index 9e390a898b..40e6a8ba5d 100644 --- a/cmd/flux/bootstrap.go +++ b/cmd/flux/bootstrap.go @@ -51,14 +51,16 @@ type bootstrapFlags struct { registry string imagePullSecret string - secretName string - tokenAuth bool - keyAlgorithm flags.PublicKeyAlgorithm - keyRSABits flags.RSAKeyBits - keyECDSACurve flags.ECDSACurve - sshHostname string - caFile string - privateKeyFile string + secretName string + tokenAuth bool + promptSSHUsername bool + keyAlgorithm flags.PublicKeyAlgorithm + keyRSABits flags.RSAKeyBits + keyECDSACurve flags.ECDSACurve + sshHostname string + caFile string + privateKeyFile string + sshUsername string watchAllNamespaces bool networkPolicy bool @@ -107,6 +109,8 @@ func init() { "deny ingress access to the toolkit controllers from other namespaces using network policies") bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.tokenAuth, "token-auth", false, "when enabled, the personal access token will be used instead of SSH deploy key") + bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.promptSSHUsername, "prompt-ssh-username", false, + "when enabled, you'll be prompted for the SSH username to override the HTTPS username") bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.logLevel, "log-level", bootstrapArgs.logLevel.Description()) bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.clusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain") bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.tolerationKeys, "toleration-keys", nil, diff --git a/cmd/flux/bootstrap_git.go b/cmd/flux/bootstrap_git.go index d553bae2d5..6c3296515c 100644 --- a/cmd/flux/bootstrap_git.go +++ b/cmd/flux/bootstrap_git.go @@ -258,6 +258,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error { bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithKubeconfig(kubeconfigArgs, kubeclientOptions), bootstrap.WithPostGenerateSecretFunc(promptPublicKey), + bootstrap.WithPromptSSHUsernameFunc(promptSSHUsername), bootstrap.WithLogger(logger), bootstrap.WithGitCommitSigning(entityList, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID), } @@ -338,3 +339,17 @@ func promptPublicKey(ctx context.Context, secret corev1.Secret, _ sourcesecret.O } return nil } + +func promptSSHUsername(ctx context.Context) (string, error) { + if !gitArgs.silent && bootstrapArgs.promptSSHUsername { + prompt := promptui.Prompt{ + Label: "Please enter the SSH username", + } + sshUsername, err := prompt.Run() + if err != nil { + return "", fmt.Errorf("aborting") + } + return sshUsername, nil + } + return "", nil +} diff --git a/pkg/bootstrap/bootstrap.go b/pkg/bootstrap/bootstrap.go index d3b79ed671..6482b24b3b 100644 --- a/pkg/bootstrap/bootstrap.go +++ b/pkg/bootstrap/bootstrap.go @@ -76,6 +76,8 @@ type RepositoryReconciler interface { type PostGenerateSecretFunc func(ctx context.Context, secret corev1.Secret, options sourcesecret.Options) error +type PromptSSHUSernameFunc func(ctx context.Context) (string, error) + func Run(ctx context.Context, reconciler Reconciler, manifestsBase string, installOpts install.Options, secretOpts sourcesecret.Options, syncOpts sync.Options, pollInterval, timeout time.Duration) error { diff --git a/pkg/bootstrap/bootstrap_plain_git.go b/pkg/bootstrap/bootstrap_plain_git.go index 476e200a84..cc674d2f0b 100644 --- a/pkg/bootstrap/bootstrap_plain_git.go +++ b/pkg/bootstrap/bootstrap_plain_git.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "io" + "net/url" "os" "path/filepath" "strings" @@ -65,6 +66,7 @@ type PlainGitBootstrapper struct { restClientOptions *runclient.Options postGenerateSecret []PostGenerateSecretFunc + promptSSHUsername PromptSSHUSernameFunc gitClient git.RepositoryClient kube client.Client @@ -95,6 +97,16 @@ func (o postGenerateSecret) applyGit(b *PlainGitBootstrapper) { b.postGenerateSecret = append(b.postGenerateSecret, PostGenerateSecretFunc(o)) } +func WithPromptSSHUsernameFunc(callback PromptSSHUSernameFunc) GitOption { + return promptSSHUsername(callback) +} + +type promptSSHUsername PromptSSHUSernameFunc + +func (o promptSSHUsername) applyGit(b *PlainGitBootstrapper) { + b.promptSSHUsername = PromptSSHUSernameFunc(o) +} + func NewPlainGitProvider(git git.RepositoryClient, kube client.Client, opts ...GitOption) (*PlainGitBootstrapper, error) { b := &PlainGitBootstrapper{ gitClient: git, @@ -276,6 +288,19 @@ func (b *PlainGitBootstrapper) ReconcileSyncConfig(ctx context.Context, options return err } + sshUsername, err := b.promptSSHUsername(ctx) + if err != nil { + return fmt.Errorf("prompting for ssh username failed: %w", err) + } + if sshUsername != "" { + repoURL, err := url.Parse(options.URL) + if err != nil { + return fmt.Errorf("unable to parse url: %w", err) + } + repoURL.User = url.User(sshUsername) + options.URL = repoURL.String() + } + // Generate sync manifests and write to Git repository b.logger.Actionf("generating sync manifests") manifests, err := sync.Generate(options)