mirror of
https://gitea.com/gitea/runner.git
synced 2026-11-04 22:37:55 +00:00
feat: Support ssh:// action URLs (#1035)
Adds `ssh://` to the list of recognized URL schemes in `newRemoteAction`, so a step can reference an action over SSH, e.g.: ```yaml uses: ssh://[email protected]/actions/checkout@v4 ``` Previously only `https://` / `http://` prefixes were parsed; an `ssh://` URL fell through to the bare `org/repo` parser and failed. ### How auth works SSH auth is delegated entirely to go-git's defaults — the runner configures no SSH-specific options: - **Which key?** go-git falls back to the host's **ssh-agent** (`$SSH_AUTH_SOCK`). There is no key-file fallback, so the agent must hold a usable key. The SSH **username** comes from the URL, so use `ssh://git@host/...` (a bare `ssh://host/...` authenticates as an empty user and most servers reject it). - **Host key trust?** Established out-of-band via the host's `known_hosts` (`$SSH_KNOWN_HOSTS`, `~/.ssh/known_hosts`, `/etc/ssh/ssh_known_hosts`). The runner host must already trust the remote; there is no accept-on-first-use. - **Host key changes?** The clone fails with a host-key-mismatch error and stays failed until `known_hosts` is updated on the host. Note `InsecureSkipTLS` does **not** apply to SSH. ### Caching The action cache path is derived from `{org}/{repo}` only (scheme/host are not part of the key), so an `ssh://` action shares cache storage with the same `org/repo` fetched over HTTP. This is unchanged by this PR and works in practice (fetches resolve by SHA), but is worth noting. ### Tests Adds `ssh://` cases to `Test_newRemoteAction` covering the scheme prefix, the `git@` username placement, and a malformed-URL rejection. The agent/known_hosts behavior lives in go-git and is not unit-tested here. Fixes #841 Reviewed-on: https://gitea.com/gitea/runner/pulls/1035 Reviewed-by: Lunny Xiao <[email protected]>
This commit is contained in:
1 parent
4997f33b5f
commit
5f0636faad
2 files changed
+27
-1
No files matched your search
@@ -312,7 +312,7 @@ func (ra *remoteAction) IsCheckout() bool {
|
||||
|
||||
func newRemoteAction(action string) *remoteAction {
|
||||
// support http(s)://host/owner/repo@v3
|
||||
for _, schema := range []string{"https://", "http://"} {
|
||||
for _, schema := range []string{"https://", "http://", "ssh://"} {
|
||||
if after, ok := strings.CutPrefix(action, schema); ok {
|
||||
splits := strings.SplitN(after, "/", 2)
|
||||
if len(splits) != 2 {
|
||||
|
||||
@@ -778,6 +778,32 @@ func Test_newRemoteAction(t *testing.T) {
|
||||
},
|
||||
wantCloneURL: "http://gitea.com/actions/aws",
|
||||
},
|
||||
{
|
||||
action: "ssh://[email protected]/actions/heroku@main", // it's invalid for GitHub, but gitea supports it
|
||||
want: &remoteAction{
|
||||
URL: "ssh://[email protected]",
|
||||
Org: "actions",
|
||||
Repo: "heroku",
|
||||
Path: "",
|
||||
Ref: "main",
|
||||
},
|
||||
wantCloneURL: "ssh://[email protected]/actions/heroku",
|
||||
},
|
||||
{
|
||||
action: "ssh://[email protected]/actions/aws/ec2@main", // the ssh user is kept as part of the host segment
|
||||
want: &remoteAction{
|
||||
URL: "ssh://[email protected]",
|
||||
Org: "actions",
|
||||
Repo: "aws",
|
||||
Path: "ec2",
|
||||
Ref: "main",
|
||||
},
|
||||
wantCloneURL: "ssh://[email protected]/actions/aws",
|
||||
},
|
||||
{
|
||||
action: "ssh://gitea.com/onlyonesegment@main", // missing org/repo after the host
|
||||
want: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.action, func(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user