mirror of
https://gitea.com/gitea/tea.git
synced 2026-06-05 18:58:43 +02:00
6dd33b5f4f
Closes #1013. ## Background While trying to use `tea` from a non-interactive context I hit a friction point: after `tea login add` succeeded, plain `git push` over HTTPS still prompted for credentials. I filed #1013 as a feature request to add credential helper integration — then found, on reading the source, that the integration **already exists**: - `tea login add` accepts `--helper` (alias `-j`), which calls `task.SetupHelper` to register a credential helper in `~/.gitconfig`. - `tea login helper get` correctly implements git's credential protocol, reading the request from stdin and returning `protocol`/`host`/`username`/`password` lines. - `tea login helper setup` does the same for every configured login. I verified end-to-end that this works as advertised: after `tea login helper setup`, an HTTPS `git push` against a configured Gitea host authenticates silently using the stored token, no prompts, with `GIT_TERMINAL_PROMPT=0` set as a safety check. So the feature is fine. The problem is that nobody can find it: | Surface | Before | Issue | |---|---|---| | Flag name on `tea login add` | `--helper` (alias `-j`) | Generic; nothing tying it to git or credentials | | Flag usage text | `"Add helper"` | Says nothing | | `tea login helper` command | `Hidden: true` | Not in `tea login --help` | | `tea login helper` usage | `"Git helper"` | Says nothing | | `tea login helper` description | `"Git helper"` | Same string again | | `store/erase` subcommand description | `"Command drops"` | Sentence fragment, no meaning | | `setup` subcommand description | `"Setup helper to tea authenticate"` | Awkward, doesn't explain what it touches | | `get` subcommand description | `"Get token to auth"` | Doesn't mention git, stdin, or the credential protocol | | Mention in `tea login add --help` | None | Feature is invisible | ## What this patch does Purely cosmetic / documentation changes — **no behavior changes**: 1. Renames `--helper` to `--git-credentials`, keeping `--helper` and `-j` as aliases so existing scripts and muscle memory keep working. 2. Removes `Hidden: true` from `tea login helper` so it appears in `tea login --help`. 3. Rewrites every placeholder `Usage` and `Description` string in the helper command tree to describe what the thing actually does. 4. Expands the top-level `Description` of `tea login add` to mention the option and explain what it does. 5. Prints a one-line hint after a successful non-helper login: `Tip: pass --git-credentials (or run 'tea login helper setup') to authenticate 'git push' and 'git clone' over HTTPS with this token.` The credential helper protocol implementation, `SetupHelper`'s gitconfig writes, and the `get`/`store`/`setup` action functions are all unchanged. ## Help output after the patch ``` $ tea login --help COMMANDS: ... helper, git-credential Act as a git credential helper for stored Gitea logins ... $ tea login helper --help NAME: tea logins helper - Act as a git credential helper for stored Gitea logins DESCRIPTION: Speaks git's credential helper protocol so that HTTPS push and clone operations against your configured Gitea instances authenticate silently using the tokens tea already stores. Typical use is automatic: 'tea login add --git-credentials' (or 'tea login helper setup' for existing logins) registers '!tea login helper' as a credential helper in ~/.gitconfig. Git then invokes the 'get' subcommand when it needs credentials for a configured host. COMMANDS: store, erase No-op (git credential protocol store/erase) setup Register tea as a git credential helper for every configured login get Return the stored token for a URL (git credential protocol) ``` ## Open questions for the reviewer A few choices in here that are subjective — happy to change any of them: - **Flag name**: `--git-credentials` was the first clear name I tried. `--credential-helper` and `--git-helper` are also reasonable. Or keep `--helper` as canonical and just fix its usage text. - **Canonical subcommand name**: I kept `helper` as canonical with `git-credential` as alias, matching what was already there. Could flip this — `gh` uses `gh auth git-credential` as canonical with no `helper` form. - **Should `--git-credentials` default to true?** Most users probably want it on; the current opt-in design surprises them. But flipping the default is a behavior change so I left it alone here. - **Should the hint be silenced by an env var or a config flag?** I left it always-on for the people who need to see it; can gate it if it bothers automation users. - **Teardown on `tea login delete`** would parallel the setup behavior, but is genuinely a separate change. Not in this PR. --- This patch was authored interactively with an AI assistant, driven and reviewed by a human (Tyler / @dinsmoor) every step. *pull request created by Tyler's lovingly wrangled demon machine <3* --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/gitea/tea/pulls/1014 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Tyler <tyler@dinsmoor.us> Co-committed-by: Tyler <tyler@dinsmoor.us>
172 lines
4.7 KiB
Go
172 lines
4.7 KiB
Go
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package login
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gitea.dev/tea/modules/auth"
|
|
"gitea.dev/tea/modules/interact"
|
|
"gitea.dev/tea/modules/task"
|
|
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
// CmdLoginAdd represents to login a gitea server.
|
|
var CmdLoginAdd = cli.Command{
|
|
Name: "add",
|
|
Usage: "Add a Gitea login",
|
|
Description: `Add a Gitea login, without args it will create one interactively.
|
|
|
|
By default tea only stores the token for its own API use. Pass --git-credentials
|
|
to also register tea as a git credential helper for the login's URL, so that
|
|
'git push' and 'git clone' over HTTPS authenticate silently using the stored
|
|
token. Equivalent to running 'tea login helper setup' afterwards.`,
|
|
ArgsUsage: " ", // command does not accept arguments
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "name",
|
|
Aliases: []string{"n"},
|
|
Usage: "Login name",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "url",
|
|
Aliases: []string{"u"},
|
|
Value: "https://gitea.com",
|
|
Sources: cli.EnvVars("GITEA_SERVER_URL"),
|
|
Usage: "Server URL",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "no-version-check",
|
|
Aliases: []string{"nv"},
|
|
Usage: "Do not check version of Gitea instance",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "token",
|
|
Aliases: []string{"t"},
|
|
Value: "",
|
|
Sources: cli.EnvVars("GITEA_SERVER_TOKEN"),
|
|
Usage: "Access token. Can be obtained from Settings > Applications",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "user",
|
|
Value: "",
|
|
Sources: cli.EnvVars("GITEA_SERVER_USER"),
|
|
Usage: "User for basic auth (will create token)",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "password",
|
|
Aliases: []string{"pwd"},
|
|
Value: "",
|
|
Sources: cli.EnvVars("GITEA_SERVER_PASSWORD"),
|
|
Usage: "Password for basic auth (will create token)",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "otp",
|
|
Sources: cli.EnvVars("GITEA_SERVER_OTP"),
|
|
Usage: "OTP token for auth, if necessary",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "scopes",
|
|
Sources: cli.EnvVars("GITEA_SCOPES"),
|
|
Usage: "Token scopes to add when creating a new token, separated by a comma",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "ssh-key",
|
|
Aliases: []string{"s"},
|
|
Usage: "Path to a SSH key/certificate to use, overrides auto-discovery",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "insecure",
|
|
Aliases: []string{"i"},
|
|
Usage: "Disable TLS verification",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "ssh-agent-principal",
|
|
Aliases: []string{"c"},
|
|
Usage: "Use SSH certificate with specified principal to login (needs a running ssh-agent with certificate loaded)",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "ssh-agent-key",
|
|
Aliases: []string{"a"},
|
|
Usage: "Use SSH public key or SSH fingerprint to login (needs a running ssh-agent with ssh key loaded)",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "git-credentials",
|
|
Aliases: []string{"helper", "j"},
|
|
Usage: "Register tea as a git credential helper for this login's URL, so 'git push' and 'git clone' over HTTPS authenticate silently using the stored token",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "oauth",
|
|
Aliases: []string{"o"},
|
|
Usage: "Use interactive OAuth2 flow for authentication",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "client-id",
|
|
Usage: "OAuth client ID (for use with --oauth)",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "redirect-url",
|
|
Usage: "OAuth redirect URL (for use with --oauth)",
|
|
},
|
|
},
|
|
Action: runLoginAdd,
|
|
}
|
|
|
|
func runLoginAdd(requestCtx context.Context, cmd *cli.Command) error {
|
|
// if no args create login interactive
|
|
if cmd.NumFlags() == 0 {
|
|
if err := interact.CreateLogin(requestCtx); err != nil && !interact.IsQuitting(err) {
|
|
return fmt.Errorf("error adding login: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// if OAuth flag is provided, use OAuth2 PKCE flow
|
|
if cmd.Bool("oauth") {
|
|
opts := auth.OAuthOptions{
|
|
Name: cmd.String("name"),
|
|
URL: cmd.String("url"),
|
|
Insecure: cmd.Bool("insecure"),
|
|
}
|
|
|
|
// Only set clientID if provided
|
|
if cmd.String("client-id") != "" {
|
|
opts.ClientID = cmd.String("client-id")
|
|
}
|
|
|
|
// Only set redirect URL if provided
|
|
if cmd.String("redirect-url") != "" {
|
|
opts.RedirectURL = cmd.String("redirect-url")
|
|
}
|
|
|
|
return auth.OAuthLoginWithFullOptions(requestCtx, opts)
|
|
}
|
|
|
|
sshAgent := false
|
|
if cmd.String("ssh-agent-key") != "" || cmd.String("ssh-agent-principal") != "" {
|
|
sshAgent = true
|
|
}
|
|
|
|
// else use args to add login
|
|
return task.CreateLogin(
|
|
requestCtx,
|
|
cmd.String("name"),
|
|
cmd.String("token"),
|
|
cmd.String("user"),
|
|
cmd.String("password"),
|
|
cmd.String("otp"),
|
|
cmd.String("scopes"),
|
|
cmd.String("ssh-key"),
|
|
cmd.String("url"),
|
|
cmd.String("ssh-agent-principal"),
|
|
cmd.String("ssh-agent-key"),
|
|
cmd.Bool("insecure"),
|
|
sshAgent,
|
|
!cmd.Bool("no-version-check"),
|
|
cmd.Bool("git-credentials"),
|
|
)
|
|
}
|