refactor(ax): dedupe sync repo parsing
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
a14feec8ab
commit
48d1eb22b0
4 changed files with 75 additions and 52 deletions
|
|
@ -8,10 +8,10 @@ import (
|
|||
os "dappco.re/go/core/scm/internal/ax/osx"
|
||||
strings "dappco.re/go/core/scm/internal/ax/stringsx"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
"net/url"
|
||||
|
||||
coreerr "dappco.re/go/core/log"
|
||||
"dappco.re/go/core/scm/agentci"
|
||||
"dappco.re/go/core/scm/cmd/internal/syncutil"
|
||||
fg "dappco.re/go/core/scm/forge"
|
||||
|
||||
forgejo "codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2"
|
||||
|
|
@ -99,7 +99,7 @@ func buildSyncRepoList(client *fg.Client, args []string, basePath string) ([]syn
|
|||
|
||||
if len(args) > 0 {
|
||||
for _, arg := range args {
|
||||
name, err := syncRepoNameFromArg(arg)
|
||||
name, err := syncutil.ParseRepoName(arg)
|
||||
if err != nil {
|
||||
return nil, coreerr.E("forge.buildSyncRepoList", "invalid repo argument", err)
|
||||
}
|
||||
|
|
@ -347,27 +347,3 @@ func syncCreateMainFromUpstream(client *fg.Client, org, repo string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func syncRepoNameFromArg(arg string) (string, error) {
|
||||
decoded, err := url.PathUnescape(arg)
|
||||
if err != nil {
|
||||
return "", coreerr.E("forge.syncRepoNameFromArg", "decode repo argument", err)
|
||||
}
|
||||
|
||||
parts := strings.Split(decoded, "/")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
return agentci.ValidatePathElement(parts[0])
|
||||
case 2:
|
||||
if _, err := agentci.ValidatePathElement(parts[0]); err != nil {
|
||||
return "", coreerr.E("forge.syncRepoNameFromArg", "invalid repo owner", err)
|
||||
}
|
||||
name, err := agentci.ValidatePathElement(parts[1])
|
||||
if err != nil {
|
||||
return "", coreerr.E("forge.syncRepoNameFromArg", "invalid repo name", err)
|
||||
}
|
||||
return name, nil
|
||||
default:
|
||||
return "", coreerr.E("forge.syncRepoNameFromArg", "repo argument must be repo or owner/repo", nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import (
|
|||
os "dappco.re/go/core/scm/internal/ax/osx"
|
||||
strings "dappco.re/go/core/scm/internal/ax/stringsx"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
"net/url"
|
||||
|
||||
coreerr "dappco.re/go/core/log"
|
||||
"dappco.re/go/core/scm/agentci"
|
||||
"dappco.re/go/core/scm/cmd/internal/syncutil"
|
||||
gt "dappco.re/go/core/scm/gitea"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
|
|
@ -100,7 +100,7 @@ func buildRepoList(client *gt.Client, args []string, basePath string) ([]repoEnt
|
|||
if len(args) > 0 {
|
||||
// Specific repos from args
|
||||
for _, arg := range args {
|
||||
name, err := repoNameFromArg(arg)
|
||||
name, err := syncutil.ParseRepoName(arg)
|
||||
if err != nil {
|
||||
return nil, coreerr.E("gitea.buildRepoList", "invalid repo argument", err)
|
||||
}
|
||||
|
|
@ -365,27 +365,3 @@ func createMainFromUpstream(client *gt.Client, org, repo string) error {
|
|||
}
|
||||
|
||||
func strPtr(s string) *string { return &s }
|
||||
|
||||
func repoNameFromArg(arg string) (string, error) {
|
||||
decoded, err := url.PathUnescape(arg)
|
||||
if err != nil {
|
||||
return "", coreerr.E("gitea.repoNameFromArg", "decode repo argument", err)
|
||||
}
|
||||
|
||||
parts := strings.Split(decoded, "/")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
return agentci.ValidatePathElement(parts[0])
|
||||
case 2:
|
||||
if _, err := agentci.ValidatePathElement(parts[0]); err != nil {
|
||||
return "", coreerr.E("gitea.repoNameFromArg", "invalid repo owner", err)
|
||||
}
|
||||
name, err := agentci.ValidatePathElement(parts[1])
|
||||
if err != nil {
|
||||
return "", coreerr.E("gitea.repoNameFromArg", "invalid repo name", err)
|
||||
}
|
||||
return name, nil
|
||||
default:
|
||||
return "", coreerr.E("gitea.repoNameFromArg", "repo argument must be repo or owner/repo", nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
37
cmd/internal/syncutil/repo_name.go
Normal file
37
cmd/internal/syncutil/repo_name.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package syncutil
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
coreerr "dappco.re/go/core/log"
|
||||
"dappco.re/go/core/scm/agentci"
|
||||
strings "dappco.re/go/core/scm/internal/ax/stringsx"
|
||||
)
|
||||
|
||||
// ParseRepoName normalises a sync argument into a validated repo name.
|
||||
// Usage: ParseRepoName(...)
|
||||
func ParseRepoName(arg string) (string, error) {
|
||||
decoded, err := url.PathUnescape(arg)
|
||||
if err != nil {
|
||||
return "", coreerr.E("syncutil.ParseRepoName", "decode repo argument", err)
|
||||
}
|
||||
|
||||
parts := strings.Split(decoded, "/")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
return agentci.ValidatePathElement(parts[0])
|
||||
case 2:
|
||||
if _, err := agentci.ValidatePathElement(parts[0]); err != nil {
|
||||
return "", coreerr.E("syncutil.ParseRepoName", "invalid repo owner", err)
|
||||
}
|
||||
name, err := agentci.ValidatePathElement(parts[1])
|
||||
if err != nil {
|
||||
return "", coreerr.E("syncutil.ParseRepoName", "invalid repo name", err)
|
||||
}
|
||||
return name, nil
|
||||
default:
|
||||
return "", coreerr.E("syncutil.ParseRepoName", "repo argument must be repo or owner/repo", nil)
|
||||
}
|
||||
}
|
||||
34
cmd/internal/syncutil/repo_name_test.go
Normal file
34
cmd/internal/syncutil/repo_name_test.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package syncutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseRepoName_Good(t *testing.T) {
|
||||
name, err := ParseRepoName("core")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "core", name)
|
||||
}
|
||||
|
||||
func TestParseRepoName_Good_OwnerRepo(t *testing.T) {
|
||||
name, err := ParseRepoName("host-uk/core")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "core", name)
|
||||
}
|
||||
|
||||
func TestParseRepoName_Bad_PathTraversal(t *testing.T) {
|
||||
_, err := ParseRepoName("../escape")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "syncutil.ParseRepoName")
|
||||
}
|
||||
|
||||
func TestParseRepoName_Bad_PathTraversalEncoded(t *testing.T) {
|
||||
_, err := ParseRepoName("host-uk%2F..%2Fescape")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "syncutil.ParseRepoName")
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue