Mirror SSH Keys -> Managed SSH Keys

This commit is contained in:
pomidorry
2026-06-03 23:25:02 +03:00
parent ab27bfc58e
commit 41f1f53b67
16 changed files with 75 additions and 75 deletions
+2 -2
View File
@@ -73,11 +73,11 @@ func GetSSHKeypairForURL(ctx context.Context, repo *repo_model.Repository, url s
return GetSSHKeypairForRepository(ctx, repo)
}
// SetupMirrorSSHAgent prepares SSH key-based authentication for a mirror or
// SetupManagedSSHAgent prepares SSH key-based authentication for a mirror or
// migration git operation against remoteURL on behalf of repo. For non-SSH
// URLs (or when no keypair is available) it is a no-op. The returned cleanup
// is never nil and must always be called by the caller (typically via defer).
func SetupMirrorSSHAgent(ctx context.Context, repo *repo_model.Repository, remoteURL string) (sshAuthSock string, cleanup func(), err error) {
func SetupManagedSSHAgent(ctx context.Context, repo *repo_model.Repository, remoteURL string) (sshAuthSock string, cleanup func(), err error) {
noop := func() {}
if !IsSSHURL(remoteURL) {
return "", noop, nil
+9 -9
View File
@@ -953,15 +953,15 @@
"settings.visibility.limited_tooltip": "Visible only to authenticated users",
"settings.visibility.private": "Private",
"settings.visibility.private_tooltip": "Visible only to members of organizations you have joined",
"settings.mirror_ssh_title": "Managed SSH Keys",
"settings.mirror_ssh_description": "Managed SSH keys allow you to authenticate with remote Git repositories using SSH for mirroring and migrations. Each user and organization has their own SSH keypair stored securely.",
"settings.mirror_ssh_current_key": "Current SSH Public Key",
"settings.mirror_ssh_fingerprint": "Fingerprint",
"settings.mirror_ssh_generate": "Generate SSH Key",
"settings.mirror_ssh_regenerate": "Regenerate SSH Key",
"settings.mirror_ssh_regenerated": "SSH keypair has been regenerated successfully.",
"settings.mirror_ssh_documentation": "SSH keys are automatically used for SSH-based repository mirrors and migrations. Add the public key to your remote Git service (GitHub, GitLab, etc.) to enable authentication.",
"settings.mirror_ssh_org_notice": "This SSH key is only for your personal repositories. For organization repositories, you need to configure SSH keys in the organization's settings.",
"settings.managed_ssh_title": "Managed SSH Keys",
"settings.managed_ssh_description": "Managed SSH keys allow you to authenticate with remote Git repositories using SSH for mirroring and migrations. Each user and organization has their own SSH keypair stored securely.",
"settings.managed_ssh_current_key": "Current SSH Public Key",
"settings.managed_ssh_fingerprint": "Fingerprint",
"settings.managed_ssh_generate": "Generate SSH Key",
"settings.managed_ssh_regenerate": "Regenerate SSH Key",
"settings.managed_ssh_regenerated": "SSH keypair has been regenerated successfully.",
"settings.managed_ssh_documentation": "SSH keys are automatically used for SSH-based repository mirrors and migrations. Add the public key to your remote Git service (GitHub, GitLab, etc.) to enable authentication.",
"settings.managed_ssh_org_notice": "This SSH key is only for your personal repositories. For organization repositories, you need to configure SSH keys in the organization's settings.",
"repo.new_repo_helper": "A repository contains all project files, including revision history. Already hosting one elsewhere? <a href=\"%s\">Migrate repository.</a>",
"repo.owner": "Owner",
"repo.owner_helper": "Some organizations may not show up in the dropdown due to a maximum repository count limit.",
+6 -6
View File
@@ -1149,9 +1149,9 @@ func Routes() *web.Router {
}, context.UserAssignmentAPI(), checkTokenPublicOnly())
}, rejectPublicOnly())
m.Group("/mirror-ssh-key", func() {
m.Get("", user.GetMirrorSSHKey)
m.Post("/regenerate", user.RegenerateMirrorSSHKey)
m.Group("/managed-ssh-key", func() {
m.Get("", user.GetManagedSSHKey)
m.Post("/regenerate", user.RegenerateManagedSSHKey)
})
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken(), contextAuthenticatedUser(), checkTokenPublicOnly())
@@ -1695,9 +1695,9 @@ func Routes() *web.Router {
})
}, reqToken(), reqOrgOwnership())
m.Group("/mirror-ssh-key", func() {
m.Get("", reqToken(), reqOrgOwnership(), org.GetMirrorSSHKey)
m.Post("/regenerate", reqToken(), reqOrgOwnership(), org.RegenerateMirrorSSHKey)
m.Group("/managed-ssh-key", func() {
m.Get("", reqToken(), reqOrgOwnership(), org.GetManagedSSHKey)
m.Post("/regenerate", reqToken(), reqOrgOwnership(), org.RegenerateManagedSSHKey)
})
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true), checkTokenPublicOnly())
m.Group("/teams/{teamid}", func() {
+6 -6
View File
@@ -11,9 +11,9 @@ import (
mirror_service "gitea.dev/services/mirror"
)
// GetMirrorSSHKey gets the SSH public key for organization mirroring
func GetMirrorSSHKey(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/mirror-ssh-key organization orgGetMirrorSSHKey
// GetManagedSSHKey gets the SSH public key for organization mirroring
func GetManagedSSHKey(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/managed-ssh-key organization orgGetManagedSSHKey
// ---
// summary: Get SSH public key for organization mirroring
// produces:
@@ -55,9 +55,9 @@ func GetMirrorSSHKey(ctx *context.APIContext) {
})
}
// RegenerateMirrorSSHKey regenerates the SSH keypair for organization mirroring
func RegenerateMirrorSSHKey(ctx *context.APIContext) {
// swagger:operation POST /orgs/{org}/mirror-ssh-key/regenerate organization orgRegenerateMirrorSSHKey
// RegenerateManagedSSHKey regenerates the SSH keypair for organization mirroring
func RegenerateManagedSSHKey(ctx *context.APIContext) {
// swagger:operation POST /orgs/{org}/managed-ssh-key/regenerate organization orgRegenerateManagedSSHKey
// ---
// summary: Regenerate SSH keypair for organization mirroring
// produces:
+6 -6
View File
@@ -11,9 +11,9 @@ import (
mirror_service "gitea.dev/services/mirror"
)
// GetMirrorSSHKey gets the SSH public key for user mirroring
func GetMirrorSSHKey(ctx *context.APIContext) {
// swagger:operation GET /user/mirror-ssh-key user userGetMirrorSSHKey
// GetManagedSSHKey gets the SSH public key for user mirroring
func GetManagedSSHKey(ctx *context.APIContext) {
// swagger:operation GET /user/managed-ssh-key user userGetManagedSSHKey
// ---
// summary: Get SSH public key for user mirroring
// produces:
@@ -47,9 +47,9 @@ func GetMirrorSSHKey(ctx *context.APIContext) {
})
}
// RegenerateMirrorSSHKey regenerates the SSH keypair for user mirroring
func RegenerateMirrorSSHKey(ctx *context.APIContext) {
// swagger:operation POST /user/mirror-ssh-key/regenerate user userRegenerateMirrorSSHKey
// RegenerateManagedSSHKey regenerates the SSH keypair for user mirroring
func RegenerateManagedSSHKey(ctx *context.APIContext) {
// swagger:operation POST /user/managed-ssh-key/regenerate user userRegenerateManagedSSHKey
// ---
// summary: Regenerate SSH keypair for user mirroring
// produces:
+1 -1
View File
@@ -51,6 +51,6 @@ func RegenerateSSHKey(ctx *context.Context) {
return
}
ctx.Flash.Success(ctx.Tr("settings.mirror_ssh_regenerated"))
ctx.Flash.Success(ctx.Tr("settings.managed_ssh_regenerated"))
ctx.Redirect(ctx.Org.OrgLink + "/settings/ssh_keys")
}
+4 -4
View File
@@ -346,7 +346,7 @@ func loadKeysData(ctx *context.Context) {
// Load SSH mirror keypair if it exists
mirrorKeypair, err := mirror_service.GetOrCreateSSHKeypairForUser(ctx, ctx.Doer.ID)
if err == nil {
ctx.Data["HasMirrorSSHKey"] = true
ctx.Data["HasManagedSSHKey"] = true
// Create a struct with the public key including comment
publicKeyWithComment, _ := mirrorKeypair.GetPublicKeyWithComment(ctx)
@@ -358,9 +358,9 @@ func loadKeysData(ctx *context.Context) {
PublicKeyWithComment: publicKeyWithComment,
}
ctx.Data["MirrorSSHKey"] = mirrorKeyData
ctx.Data["ManagedSSHKey"] = mirrorKeyData
} else {
ctx.Data["HasMirrorSSHKey"] = false
ctx.Data["HasManagedSSHKey"] = false
}
}
@@ -372,6 +372,6 @@ func RegenerateUserSSHKeypair(ctx *context.Context) {
return
}
ctx.Flash.Success(ctx.Tr("settings.mirror_ssh_regenerated"))
ctx.Flash.Success(ctx.Tr("settings.managed_ssh_regenerated"))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
}
+1 -1
View File
@@ -118,7 +118,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
// Setup SSH authentication if needed
sshAuthSock, cleanup, sshErr := SetupMirrorSSHAgent(ctx, m.Repo, remoteURL.String())
sshAuthSock, cleanup, sshErr := SetupManagedSSHAgent(ctx, m.Repo, remoteURL.String())
if sshErr != nil {
log.Error("SyncMirrors [repo: %-v]: SSH setup error %v", m.Repo, sshErr)
return nil, false
+1 -1
View File
@@ -167,7 +167,7 @@ func runPushSync(ctx context.Context, m *repo_model.PushMirror) error {
}
// Setup SSH authentication
sshAuthSock, cleanup, err := SetupMirrorSSHAgent(ctx, repo, remoteURL.String())
sshAuthSock, cleanup, err := SetupManagedSSHAgent(ctx, repo, remoteURL.String())
if err != nil {
log.Error("Failed to set up SSH agent for push mirror %s: %v", repo.FullName(), err)
return util.SanitizeErrorCredentialURLs(err)
+3 -3
View File
@@ -51,9 +51,9 @@ func GetSSHKeypairForURL(ctx context.Context, repo *repo_model.Repository, url s
return ssh_module.GetSSHKeypairForURL(ctx, repo, url)
}
// SetupMirrorSSHAgent prepares SSH key-based authentication for a mirror or
// SetupManagedSSHAgent prepares SSH key-based authentication for a mirror or
// migration git operation against url on behalf of repo. The returned cleanup
// is never nil and must always be called by the caller (typically via defer).
func SetupMirrorSSHAgent(ctx context.Context, repo *repo_model.Repository, url string) (string, func(), error) {
return ssh_module.SetupMirrorSSHAgent(ctx, repo, url)
func SetupManagedSSHAgent(ctx context.Context, repo *repo_model.Repository, url string) (string, func(), error) {
return ssh_module.SetupManagedSSHAgent(ctx, repo, url)
}
+1 -1
View File
@@ -29,7 +29,7 @@ import (
)
func cloneExternalRepoWithSSHAuth(ctx context.Context, repo *repo_model.Repository, remoteURL string, storageRepo gitrepo.Repository, cloneOpts git.CloneRepoOptions) error {
sshAuthSock, cleanup, err := ssh_module.SetupMirrorSSHAgent(ctx, repo, remoteURL)
sshAuthSock, cleanup, err := ssh_module.SetupManagedSSHAgent(ctx, repo, remoteURL)
if err != nil {
return err
}
+7 -7
View File
@@ -2,23 +2,23 @@
<div class="ui segments org-setting-content">
<h4 class="ui top attached header">
{{ctx.Locale.Tr "settings.mirror_ssh_title"}}
{{ctx.Locale.Tr "settings.managed_ssh_title"}}
</h4>
<div class="ui attached segment">
<div class="ui form">
<div class="field">
<label>{{ctx.Locale.Tr "settings.mirror_ssh_description"}}</label>
<label>{{ctx.Locale.Tr "settings.managed_ssh_description"}}</label>
</div>
{{if .SSHKeypair}}
<div class="field">
<label>{{ctx.Locale.Tr "settings.mirror_ssh_current_key"}}</label>
<label>{{ctx.Locale.Tr "settings.managed_ssh_current_key"}}</label>
<div class="ui action input">
<input id="ssh-public-key-content" class="js-ssh-key-content" value="{{.SSHKeypair.PublicKey}}" readonly>
<button class="ui compact button" data-clipboard-target="#ssh-public-key-content" data-tooltip-content="{{ctx.Locale.Tr "copy"}}">
{{svg "octicon-copy" 14}}
</button>
</div>
<small class="text grey">{{ctx.Locale.Tr "settings.mirror_ssh_fingerprint"}}: {{.SSHKeypair.Fingerprint}}</small>
<small class="text grey">{{ctx.Locale.Tr "settings.managed_ssh_fingerprint"}}: {{.SSHKeypair.Fingerprint}}</small>
</div>
{{end}}
<div class="field">
@@ -26,9 +26,9 @@
{{.CsrfTokenHtml}}
<button class="ui primary button" type="submit">
{{if .SSHKeypair}}
{{ctx.Locale.Tr "settings.mirror_ssh_regenerate"}}
{{ctx.Locale.Tr "settings.managed_ssh_regenerate"}}
{{else}}
{{ctx.Locale.Tr "settings.mirror_ssh_generate"}}
{{ctx.Locale.Tr "settings.managed_ssh_generate"}}
{{end}}
</button>
</form>
@@ -36,7 +36,7 @@
<div class="field">
<div class="ui info message">
<i class="info icon"></i>
{{ctx.Locale.Tr "settings.mirror_ssh_documentation"}}
{{ctx.Locale.Tr "settings.managed_ssh_documentation"}}
</div>
</div>
</div>
+8 -8
View File
@@ -3378,7 +3378,7 @@
}
}
},
"/orgs/{org}/mirror-ssh-key": {
"/orgs/{org}/managed-ssh-key": {
"get": {
"produces": [
"application/json"
@@ -3387,7 +3387,7 @@
"organization"
],
"summary": "Get SSH public key for organization mirroring",
"operationId": "orgGetMirrorSSHKey",
"operationId": "orgGetManagedSSHKey",
"parameters": [
{
"type": "string",
@@ -3421,7 +3421,7 @@
}
}
},
"/orgs/{org}/mirror-ssh-key/regenerate": {
"/orgs/{org}/managed-ssh-key/regenerate": {
"post": {
"produces": [
"application/json"
@@ -3430,7 +3430,7 @@
"organization"
],
"summary": "Regenerate SSH keypair for organization mirroring",
"operationId": "orgRegenerateMirrorSSHKey",
"operationId": "orgRegenerateManagedSSHKey",
"parameters": [
{
"type": "string",
@@ -20524,7 +20524,7 @@
}
}
},
"/user/mirror-ssh-key": {
"/user/managed-ssh-key": {
"get": {
"produces": [
"application/json"
@@ -20533,7 +20533,7 @@
"user"
],
"summary": "Get SSH public key for user mirroring",
"operationId": "userGetMirrorSSHKey",
"operationId": "userGetManagedSSHKey",
"responses": {
"200": {
"description": "SSH public key",
@@ -20555,7 +20555,7 @@
}
}
},
"/user/mirror-ssh-key/regenerate": {
"/user/managed-ssh-key/regenerate": {
"post": {
"produces": [
"application/json"
@@ -20564,7 +20564,7 @@
"user"
],
"summary": "Regenerate SSH keypair for user mirroring",
"operationId": "userRegenerateMirrorSSHKey",
"operationId": "userRegenerateManagedSSHKey",
"responses": {
"200": {
"description": "New SSH public key",
+8 -8
View File
@@ -14106,9 +14106,9 @@
]
}
},
"/orgs/{org}/mirror-ssh-key": {
"/orgs/{org}/managed-ssh-key": {
"get": {
"operationId": "orgGetMirrorSSHKey",
"operationId": "orgGetManagedSSHKey",
"parameters": [
{
"description": "name of the organization",
@@ -14152,9 +14152,9 @@
]
}
},
"/orgs/{org}/mirror-ssh-key/regenerate": {
"/orgs/{org}/managed-ssh-key/regenerate": {
"post": {
"operationId": "orgRegenerateMirrorSSHKey",
"operationId": "orgRegenerateManagedSSHKey",
"parameters": [
{
"description": "name of the organization",
@@ -32569,9 +32569,9 @@
]
}
},
"/user/mirror-ssh-key": {
"/user/managed-ssh-key": {
"get": {
"operationId": "userGetMirrorSSHKey",
"operationId": "userGetManagedSSHKey",
"responses": {
"200": {
"content": {
@@ -32601,9 +32601,9 @@
]
}
},
"/user/mirror-ssh-key/regenerate": {
"/user/managed-ssh-key/regenerate": {
"post": {
"operationId": "userRegenerateMirrorSSHKey",
"operationId": "userRegenerateManagedSSHKey",
"responses": {
"200": {
"content": {
+1 -1
View File
@@ -8,6 +8,6 @@
{{template "user/settings/keys_gpg" .}}
{{end}}
<div class="ui divider"></div>
{{template "user/settings/keys_mirror_ssh" .}}
{{template "user/settings/keys_managed_ssh" .}}
</div>
{{template "user/settings/layout_footer" .}}
@@ -1,31 +1,31 @@
<h4 class="ui top attached header">
{{ctx.Locale.Tr "settings.mirror_ssh_title"}}
{{ctx.Locale.Tr "settings.managed_ssh_title"}}
</h4>
<div class="ui attached segment">
<div class="ui form">
<div class="field">
<label>{{ctx.Locale.Tr "settings.mirror_ssh_description"}}</label>
<label>{{ctx.Locale.Tr "settings.managed_ssh_description"}}</label>
</div>
{{if .HasMirrorSSHKey}}
{{if .HasManagedSSHKey}}
<div class="field">
<label>{{ctx.Locale.Tr "settings.mirror_ssh_current_key"}}</label>
<label>{{ctx.Locale.Tr "settings.managed_ssh_current_key"}}</label>
<div class="ui action input">
<input id="ssh-public-key-content" class="js-ssh-key-content" value="{{.MirrorSSHKey.PublicKeyWithComment}}" readonly>
<input id="ssh-public-key-content" class="js-ssh-key-content" value="{{.ManagedSSHKey.PublicKeyWithComment}}" readonly>
<button class="ui compact button" data-clipboard-target="#ssh-public-key-content" data-tooltip-content="{{ctx.Locale.Tr "copy"}}">
{{svg "octicon-copy" 14}}
</button>
</div>
<small class="text grey">{{ctx.Locale.Tr "settings.mirror_ssh_fingerprint"}}: {{.MirrorSSHKey.Fingerprint}}</small>
<small class="text grey">{{ctx.Locale.Tr "settings.managed_ssh_fingerprint"}}: {{.ManagedSSHKey.Fingerprint}}</small>
</div>
{{end}}
<div class="field">
<form action="{{.Link}}/mirror-ssh/regenerate" method="post">
{{.CsrfTokenHtml}}
<button class="ui primary button" type="submit">
{{if .HasMirrorSSHKey}}
{{ctx.Locale.Tr "settings.mirror_ssh_regenerate"}}
{{if .HasManagedSSHKey}}
{{ctx.Locale.Tr "settings.managed_ssh_regenerate"}}
{{else}}
{{ctx.Locale.Tr "settings.mirror_ssh_generate"}}
{{ctx.Locale.Tr "settings.managed_ssh_generate"}}
{{end}}
</button>
</form>
@@ -33,13 +33,13 @@
<div class="field">
<div class="ui info message">
<i class="info icon"></i>
{{ctx.Locale.Tr "settings.mirror_ssh_documentation"}}
{{ctx.Locale.Tr "settings.managed_ssh_documentation"}}
</div>
</div>
<div class="field">
<div class="ui warning message">
<i class="warning icon"></i>
{{ctx.Locale.Tr "settings.mirror_ssh_org_notice"}}
{{ctx.Locale.Tr "settings.managed_ssh_org_notice"}}
</div>
</div>
</div>