1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-08-01 21:23:39 +02:00

Allow git in git-obs to be switched from SSH to http(s)

This commit is contained in:
2025-06-18 13:51:32 +02:00
parent c5193f1187
commit 78066f8e70
7 changed files with 113 additions and 1 deletions

View File

@@ -25,3 +25,37 @@ Scenario: Clone a git repo
Total cloned repos: 1
"""
@destructive
Scenario: Clone a git repo via http
Given I execute git-obs with args "api -X PATCH /repos/pool/test-GitPkgA/ --data '{{"private": true}}'"
And stdout contains ""private": true"
And I execute git-obs with args "login update admin --new-git-uses-http=1 --new-ssh-key="
When I set env "GIT_TERMINAL_PROMPT" to "0"
And I execute git-obs with args "repo clone pool/test-GitPkgA --no-ssh-strict-host-key-checking"
Then the exit code is 1
Given I create file "{context.osc.temp}/gitconfig" with perms "0644"
"""
[credential "http://localhost:{context.podman.container.ports[gitea_http]}"]
helper = "{context.git_obs.cmd} -G admin login gitcredentials-helper"
"""
And I set env "GIT_CONFIG_GLOBAL" to "{context.osc.temp}/gitconfig"
When I execute git-obs with args "repo clone pool/test-GitPkgA --no-ssh-strict-host-key-checking"
Then the exit code is 0
And stdout is
"""
"""
And stderr is
"""
Using the following Gitea settings:
* Config path: {context.git_obs.config}
* Login (name of the entry in the config file): admin
* URL: http://localhost:{context.podman.container.ports[gitea_http]}
* User: Admin
Cloning git repo pool/test-GitPkgA ...
Cloning into 'test-GitPkgA'...
Total cloned repos: 1
"""

View File

@@ -65,6 +65,22 @@ Use one of the following commands to upload your public SSH key to the Gitea ser
git-obs ssh-key add --key-path PUBLIC_KEY_PATH
Using git with token auth instead of SSH keys
=============================================
It is possible to use Gitea token for both communicating with the Gitea API
and also for authenticating the git command.
To use token auth for git operations, switch git from using SSH to http(s)::
git-obs login update <login> --new-git-uses-http=1
and add the following entry to ~/.config/git/config or ~/.gitconfig::
[credential "https://src.example.com"]
helper = "git-obs -G <login> login gitcredentials-helper"
Workflow: Making changes to packages
====================================

View File

@@ -21,6 +21,7 @@ class LoginAddCommand(osc.commandline_git.GitObsCommand):
self.parser.add_argument("--user", help="Gitea username", required=True)
self.parser.add_argument("--token", help="Gitea access token; omit or set to '-' to invoke a secure interactive prompt")
self.parser.add_argument("--ssh-key", metavar="PATH", help="Path to a private SSH key").completer = complete_ssh_key_path
self.parser.add_argument("--git-uses-http", action="store_true", help="Git uses http(s) instead of SSH", default=None)
self.parser.add_argument("--set-as-default", help="Set the new login entry as default", action="store_true", default=None)
def run(self, args):
@@ -44,6 +45,7 @@ class LoginAddCommand(osc.commandline_git.GitObsCommand):
user=args.user,
token=args.token,
ssh_key=args.ssh_key,
git_uses_http=args.git_uses_http,
default=args.set_as_default,
)
self.gitea_conf.add_login(login_obj)

View File

@@ -0,0 +1,32 @@
import osc.commandline_git
class LoginGitcredentialsHelperCommand(osc.commandline_git.GitObsCommand):
"""
A gitcredentials helper
To use token auth for git operations, switch git from using SSH to http(s):
git-obs login update <login> --new-git-uses-http=1
and add the following entry to .gitconfig:
[credential "https://src.example.com"]
helper = "git-obs -G <login> login gitcredentials-helper"
"""
name = "gitcredentials-helper"
parent = "LoginCommand"
hidden = True
def init_arguments(self):
self.parser.add_argument(
"operation",
# see gitcredentials(7) for more details
choices=["get", "store", "erase"],
)
def run(self, args):
import shlex
if args.operation == "get":
print(f"username={shlex.quote(self.gitea_login.user)}")
print(f"password={shlex.quote(self.gitea_login.token)}")

View File

@@ -22,6 +22,7 @@ class LoginUpdateCommand(osc.commandline_git.GitObsCommand):
self.parser.add_argument("--new-user", metavar="USER", help="Gitea username")
self.parser.add_argument("--new-token", metavar="TOKEN", help="Gitea access token; set to '-' to invoke a secure interactive prompt")
self.parser.add_argument("--new-ssh-key", metavar="PATH", help="Path to a private SSH key").completer = complete_ssh_key_path
self.parser.add_argument("--new-git-uses-http", help="Git uses http(s) instead of SSH", choices=["0", "1", "yes", "no"], default=None)
self.parser.add_argument("--set-as-default", action="store_true", help="Set the login entry as default")
def run(self, args):
@@ -43,6 +44,13 @@ class LoginUpdateCommand(osc.commandline_git.GitObsCommand):
if args.new_token and not re.match(r"^[0-9a-f]{40}$", args.new_token):
self.parser.error("Invalid token format, 40 hexadecimal characters expected")
if args.new_git_uses_http in ("0", "no"):
new_git_uses_http = False
elif args.new_git_uses_http in ("1", "yes"):
new_git_uses_http = True
else:
new_git_uses_http = None
updated_login_obj = self.gitea_conf.update_login(
args.name,
new_name=args.new_name,
@@ -50,6 +58,7 @@ class LoginUpdateCommand(osc.commandline_git.GitObsCommand):
new_user=args.new_user,
new_token=args.new_token,
new_ssh_key=args.new_ssh_key,
new_git_uses_http=new_git_uses_http,
set_as_default=args.set_as_default,
)
print("")

View File

@@ -64,7 +64,7 @@ class RepoCloneCommand(osc.commandline_git.GitObsCommand):
owner,
repo,
directory=args.directory,
use_http=args.anonymous,
use_http=args.anonymous or self.gitea_login.git_uses_http,
add_remotes=True,
ssh_private_key_path=args.ssh_key or self.gitea_login.ssh_key,
ssh_strict_host_key_checking=not(args.no_ssh_strict_host_key_checking),

View File

@@ -21,6 +21,7 @@ class Login(BaseModel):
user: str = Field() # type: ignore[assignment]
token: str = Field() # type: ignore[assignment]
ssh_key: Optional[str] = Field() # type: ignore[assignment]
git_uses_http: Optional[bool] = Field() # type: ignore[assignment]
default: Optional[bool] = Field() # type: ignore[assignment]
class AlreadyExists(oscerr.OscBaseError):
@@ -67,6 +68,8 @@ class Login(BaseModel):
table.add("User", self.user)
if self.ssh_key:
table.add("Private SSH key path", self.ssh_key)
if self.git_uses_http:
table.add("Git uses http(s)", "yes" if self.git_uses_http else "no")
if show_token:
# tokens are stored in the plain text, there's not reason to protect them too much
# let's only hide them from the output by default
@@ -217,6 +220,7 @@ class Config:
new_user: Optional[str] = None,
new_token: Optional[str] = None,
new_ssh_key: Optional[str] = None,
new_git_uses_http: Optional[bool] = None,
set_as_default: Optional[bool] = None,
) -> Login:
login = self.get_login(name)
@@ -231,6 +235,16 @@ class Config:
login.token = new_token
if new_ssh_key is not None:
login.ssh_key = new_ssh_key
if new_git_uses_http is None:
# keep the original value
pass
elif new_git_uses_http:
login.git_uses_http = True
else:
# remove from the config instead of setting to False
login.git_uses_http = None
if set_as_default:
login.default = True
@@ -241,6 +255,11 @@ class Config:
for entry in data["logins"]:
if entry.get("name", None) == name:
entry.update(login.dict())
# remove keys with no value
for key, value in entry.copy().items():
if value is None:
del entry[key]
else:
if set_as_default:
entry.pop("default", None)