mirror of
https://github.com/openSUSE/osc.git
synced 2025-08-22 22:48:51 +02:00
Allow git in git-obs to be switched from SSH to http(s)
This commit is contained in:
@@ -25,3 +25,37 @@ Scenario: Clone a git repo
|
|||||||
|
|
||||||
Total cloned repos: 1
|
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
|
||||||
|
"""
|
||||||
|
@@ -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
|
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
|
Workflow: Making changes to packages
|
||||||
====================================
|
====================================
|
||||||
|
@@ -21,6 +21,7 @@ class LoginAddCommand(osc.commandline_git.GitObsCommand):
|
|||||||
self.parser.add_argument("--user", help="Gitea username", required=True)
|
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("--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("--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)
|
self.parser.add_argument("--set-as-default", help="Set the new login entry as default", action="store_true", default=None)
|
||||||
|
|
||||||
def run(self, args):
|
def run(self, args):
|
||||||
@@ -44,6 +45,7 @@ class LoginAddCommand(osc.commandline_git.GitObsCommand):
|
|||||||
user=args.user,
|
user=args.user,
|
||||||
token=args.token,
|
token=args.token,
|
||||||
ssh_key=args.ssh_key,
|
ssh_key=args.ssh_key,
|
||||||
|
git_uses_http=args.git_uses_http,
|
||||||
default=args.set_as_default,
|
default=args.set_as_default,
|
||||||
)
|
)
|
||||||
self.gitea_conf.add_login(login_obj)
|
self.gitea_conf.add_login(login_obj)
|
||||||
|
32
osc/commands_git/login_gitcredentials_helper.py
Normal file
32
osc/commands_git/login_gitcredentials_helper.py
Normal 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)}")
|
@@ -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-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-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-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")
|
self.parser.add_argument("--set-as-default", action="store_true", help="Set the login entry as default")
|
||||||
|
|
||||||
def run(self, args):
|
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):
|
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")
|
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(
|
updated_login_obj = self.gitea_conf.update_login(
|
||||||
args.name,
|
args.name,
|
||||||
new_name=args.new_name,
|
new_name=args.new_name,
|
||||||
@@ -50,6 +58,7 @@ class LoginUpdateCommand(osc.commandline_git.GitObsCommand):
|
|||||||
new_user=args.new_user,
|
new_user=args.new_user,
|
||||||
new_token=args.new_token,
|
new_token=args.new_token,
|
||||||
new_ssh_key=args.new_ssh_key,
|
new_ssh_key=args.new_ssh_key,
|
||||||
|
new_git_uses_http=new_git_uses_http,
|
||||||
set_as_default=args.set_as_default,
|
set_as_default=args.set_as_default,
|
||||||
)
|
)
|
||||||
print("")
|
print("")
|
||||||
|
@@ -64,7 +64,7 @@ class RepoCloneCommand(osc.commandline_git.GitObsCommand):
|
|||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
directory=args.directory,
|
directory=args.directory,
|
||||||
use_http=args.anonymous,
|
use_http=args.anonymous or self.gitea_login.git_uses_http,
|
||||||
add_remotes=True,
|
add_remotes=True,
|
||||||
ssh_private_key_path=args.ssh_key or self.gitea_login.ssh_key,
|
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),
|
ssh_strict_host_key_checking=not(args.no_ssh_strict_host_key_checking),
|
||||||
|
@@ -21,6 +21,7 @@ class Login(BaseModel):
|
|||||||
user: str = Field() # type: ignore[assignment]
|
user: str = Field() # type: ignore[assignment]
|
||||||
token: str = Field() # type: ignore[assignment]
|
token: str = Field() # type: ignore[assignment]
|
||||||
ssh_key: Optional[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]
|
default: Optional[bool] = Field() # type: ignore[assignment]
|
||||||
|
|
||||||
class AlreadyExists(oscerr.OscBaseError):
|
class AlreadyExists(oscerr.OscBaseError):
|
||||||
@@ -67,6 +68,8 @@ class Login(BaseModel):
|
|||||||
table.add("User", self.user)
|
table.add("User", self.user)
|
||||||
if self.ssh_key:
|
if self.ssh_key:
|
||||||
table.add("Private SSH key path", 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:
|
if show_token:
|
||||||
# tokens are stored in the plain text, there's not reason to protect them too much
|
# 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
|
# let's only hide them from the output by default
|
||||||
@@ -217,6 +220,7 @@ class Config:
|
|||||||
new_user: Optional[str] = None,
|
new_user: Optional[str] = None,
|
||||||
new_token: Optional[str] = None,
|
new_token: Optional[str] = None,
|
||||||
new_ssh_key: Optional[str] = None,
|
new_ssh_key: Optional[str] = None,
|
||||||
|
new_git_uses_http: Optional[bool] = None,
|
||||||
set_as_default: Optional[bool] = None,
|
set_as_default: Optional[bool] = None,
|
||||||
) -> Login:
|
) -> Login:
|
||||||
login = self.get_login(name)
|
login = self.get_login(name)
|
||||||
@@ -231,6 +235,16 @@ class Config:
|
|||||||
login.token = new_token
|
login.token = new_token
|
||||||
if new_ssh_key is not None:
|
if new_ssh_key is not None:
|
||||||
login.ssh_key = new_ssh_key
|
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:
|
if set_as_default:
|
||||||
login.default = True
|
login.default = True
|
||||||
|
|
||||||
@@ -241,6 +255,11 @@ class Config:
|
|||||||
for entry in data["logins"]:
|
for entry in data["logins"]:
|
||||||
if entry.get("name", None) == name:
|
if entry.get("name", None) == name:
|
||||||
entry.update(login.dict())
|
entry.update(login.dict())
|
||||||
|
|
||||||
|
# remove keys with no value
|
||||||
|
for key, value in entry.copy().items():
|
||||||
|
if value is None:
|
||||||
|
del entry[key]
|
||||||
else:
|
else:
|
||||||
if set_as_default:
|
if set_as_default:
|
||||||
entry.pop("default", None)
|
entry.pop("default", None)
|
||||||
|
Reference in New Issue
Block a user