loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request '[FIX] Don't allow SSH authentication without ssh executable' (#5123) from gusted/forgejo-prevent-no-ssh into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5123
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>

+80
+6
modules/git/git.go
··· 38 38 InvertedGitFlushEnv bool // 2.43.1 39 39 SupportCheckAttrOnBare bool // >= 2.40 40 40 41 + HasSSHExecutable bool 42 + 41 43 gitVersion *version.Version 42 44 ) 43 45 ··· 202 204 } 203 205 globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") 204 206 } 207 + 208 + // Detect the presence of the ssh executable in $PATH. 209 + _, err = exec.LookPath("ssh") 210 + HasSSHExecutable = err == nil 205 211 206 212 return syncGitConfig() 207 213 }
+1
options/locale/locale_en-US.ini
··· 1105 1105 mirror_public_key = Public SSH key 1106 1106 mirror_use_ssh.text = Use SSH authentication 1107 1107 mirror_use_ssh.helper = Forgejo will mirror the repository via Git over SSH and create a keypair for you when you select this option. You must ensure that the generated public key is authorized to push to the destination repository. You cannot use password-based authorization when selecting this. 1108 + mirror_use_ssh.not_available = SSH authentication isn't available. 1108 1109 mirror_denied_combination = Cannot use public key and password based authentication in combination. 1109 1110 mirror_sync = synced 1110 1111 mirror_sync_on_commit = Sync when commits are pushed
+6
routers/api/v1/repo/mirror.go
··· 13 13 "code.gitea.io/gitea/models/db" 14 14 repo_model "code.gitea.io/gitea/models/repo" 15 15 "code.gitea.io/gitea/models/unit" 16 + "code.gitea.io/gitea/modules/git" 16 17 "code.gitea.io/gitea/modules/setting" 17 18 api "code.gitea.io/gitea/modules/structs" 18 19 "code.gitea.io/gitea/modules/util" ··· 347 348 interval, err := time.ParseDuration(mirrorOption.Interval) 348 349 if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) { 349 350 ctx.Error(http.StatusBadRequest, "CreatePushMirror", err) 351 + return 352 + } 353 + 354 + if mirrorOption.UseSSH && !git.HasSSHExecutable { 355 + ctx.Error(http.StatusBadRequest, "CreatePushMirror", "SSH authentication not available.") 350 356 return 351 357 } 352 358
+6
routers/web/repo/setting/setting.go
··· 92 92 return 93 93 } 94 94 ctx.Data["PushMirrors"] = pushMirrors 95 + ctx.Data["CanUseSSHMirroring"] = git.HasSSHExecutable 95 96 } 96 97 97 98 // Units show a repositorys unit settings page ··· 640 641 if form.PushMirrorUseSSH && (form.PushMirrorUsername != "" || form.PushMirrorPassword != "") { 641 642 ctx.Data["Err_PushMirrorUseSSH"] = true 642 643 ctx.RenderWithErr(ctx.Tr("repo.mirror_denied_combination"), tplSettingsOptions, &form) 644 + return 645 + } 646 + 647 + if form.PushMirrorUseSSH && !git.HasSSHExecutable { 648 + ctx.RenderWithErr(ctx.Tr("repo.mirror_use_ssh.not_available"), tplSettingsOptions, &form) 643 649 return 644 650 } 645 651
+2
templates/repo/settings/options.tmpl
··· 300 300 <label for="push_mirror_password">{{ctx.Locale.Tr "password"}}</label> 301 301 <input id="push_mirror_password" name="push_mirror_password" type="password" value="{{.push_mirror_password}}" autocomplete="off"> 302 302 </div> 303 + {{if .CanUseSSHMirroring}} 303 304 <div class="inline field {{if .Err_PushMirrorUseSSH}}error{{end}}"> 304 305 <div class="ui checkbox df ac"> 305 306 <input id="push_mirror_use_ssh" name="push_mirror_use_ssh" type="checkbox" {{if .push_mirror_use_ssh}}checked{{end}}> ··· 307 308 <span class="help tw-block">{{ctx.Locale.Tr "repo.mirror_use_ssh.helper"}} 308 309 </div> 309 310 </div> 311 + {{end}} 310 312 </div> 311 313 </details> 312 314 <div class="field">
+23
tests/integration/api_push_mirror_test.go
··· 11 11 "net/http" 12 12 "net/url" 13 13 "os" 14 + "os/exec" 14 15 "path/filepath" 15 16 "strconv" 16 17 "testing" ··· 23 24 "code.gitea.io/gitea/models/unit" 24 25 "code.gitea.io/gitea/models/unittest" 25 26 user_model "code.gitea.io/gitea/models/user" 27 + "code.gitea.io/gitea/modules/git" 26 28 "code.gitea.io/gitea/modules/optional" 27 29 "code.gitea.io/gitea/modules/setting" 28 30 api "code.gitea.io/gitea/modules/structs" ··· 141 143 } 142 144 143 145 func TestAPIPushMirrorSSH(t *testing.T) { 146 + _, err := exec.LookPath("ssh") 147 + if err != nil { 148 + t.Skip("SSH executable not present") 149 + } 150 + 144 151 onGiteaRun(t, func(t *testing.T, _ *url.URL) { 145 152 defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() 146 153 defer test.MockVariableValue(&setting.Mirror.Enabled, true)() ··· 176 183 var apiError api.APIError 177 184 DecodeJSON(t, resp, &apiError) 178 185 assert.EqualValues(t, "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'", apiError.Message) 186 + }) 187 + 188 + t.Run("SSH not available", func(t *testing.T) { 189 + defer tests.PrintCurrentTest(t)() 190 + defer test.MockVariableValue(&git.HasSSHExecutable, false)() 191 + 192 + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName()), &api.CreatePushMirrorOption{ 193 + RemoteAddress: sshURL, 194 + Interval: "8h", 195 + UseSSH: true, 196 + }).AddTokenAuth(token) 197 + resp := MakeRequest(t, req, http.StatusBadRequest) 198 + 199 + var apiError api.APIError 200 + DecodeJSON(t, resp, &apiError) 201 + assert.EqualValues(t, "SSH authentication not available.", apiError.Message) 179 202 }) 180 203 181 204 t.Run("Normal", func(t *testing.T) {
+36
tests/integration/mirror_push_test.go
··· 11 11 "net/http" 12 12 "net/url" 13 13 "os" 14 + "os/exec" 14 15 "path/filepath" 15 16 "strconv" 16 17 "testing" ··· 157 158 } 158 159 159 160 func TestSSHPushMirror(t *testing.T) { 161 + _, err := exec.LookPath("ssh") 162 + if err != nil { 163 + t.Skip("SSH executable not present") 164 + } 165 + 160 166 onGiteaRun(t, func(t *testing.T, _ *url.URL) { 161 167 defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() 162 168 defer test.MockVariableValue(&setting.Mirror.Enabled, true)() ··· 192 198 193 199 errMsg := htmlDoc.Find(".ui.negative.message").Text() 194 200 assert.Contains(t, errMsg, "Cannot use public key and password based authentication in combination.") 201 + }) 202 + 203 + inputSelector := `input[id="push_mirror_use_ssh"]` 204 + 205 + t.Run("SSH not available", func(t *testing.T) { 206 + defer tests.PrintCurrentTest(t)() 207 + defer test.MockVariableValue(&git.HasSSHExecutable, false)() 208 + 209 + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/settings", srcRepo.FullName()), map[string]string{ 210 + "_csrf": GetCSRF(t, sess, fmt.Sprintf("/%s/settings", srcRepo.FullName())), 211 + "action": "push-mirror-add", 212 + "push_mirror_address": sshURL, 213 + "push_mirror_use_ssh": "true", 214 + "push_mirror_interval": "0", 215 + }) 216 + resp := sess.MakeRequest(t, req, http.StatusOK) 217 + htmlDoc := NewHTMLParser(t, resp.Body) 218 + 219 + errMsg := htmlDoc.Find(".ui.negative.message").Text() 220 + assert.Contains(t, errMsg, "SSH authentication isn't available.") 221 + 222 + htmlDoc.AssertElement(t, inputSelector, false) 223 + }) 224 + 225 + t.Run("SSH available", func(t *testing.T) { 226 + req := NewRequest(t, "GET", fmt.Sprintf("/%s/settings", srcRepo.FullName())) 227 + resp := sess.MakeRequest(t, req, http.StatusOK) 228 + 229 + htmlDoc := NewHTMLParser(t, resp.Body) 230 + htmlDoc.AssertElement(t, inputSelector, true) 195 231 }) 196 232 197 233 t.Run("Normal", func(t *testing.T) {