fix: resolve lint issues in handlers and middleware
All checks were successful
Check / check (pull_request) Successful in 11m26s

This commit is contained in:
clawbot 2026-02-20 03:35:44 -08:00
parent 6cfd5023f9
commit 327d7fb982
5 changed files with 66 additions and 42 deletions

View File

@ -176,9 +176,8 @@ func (h *Handlers) HandleAPIGetApp() http.HandlerFunc {
} }
} }
// HandleAPICreateApp returns a handler that creates a new app. // apiCreateRequest is the JSON body for creating an app via the API.
func (h *Handlers) HandleAPICreateApp() http.HandlerFunc { type apiCreateRequest struct {
type createRequest struct {
Name string `json:"name"` Name string `json:"name"`
RepoURL string `json:"repoUrl"` RepoURL string `json:"repoUrl"`
Branch string `json:"branch"` Branch string `json:"branch"`
@ -186,10 +185,32 @@ func (h *Handlers) HandleAPICreateApp() http.HandlerFunc {
DockerNetwork string `json:"dockerNetwork"` DockerNetwork string `json:"dockerNetwork"`
NtfyTopic string `json:"ntfyTopic"` NtfyTopic string `json:"ntfyTopic"`
SlackWebhook string `json:"slackWebhook"` SlackWebhook string `json:"slackWebhook"`
}
// validateCreateRequest validates the fields of an API create app request.
// Returns an error message string or empty string if valid.
func validateCreateRequest(req *apiCreateRequest) string {
if req.Name == "" || req.RepoURL == "" {
return "name and repo_url are required"
} }
nameErr := validateAppName(req.Name)
if nameErr != nil {
return "invalid app name: " + nameErr.Error()
}
repoURLErr := validateRepoURL(req.RepoURL)
if repoURLErr != nil {
return "invalid repository URL: " + repoURLErr.Error()
}
return ""
}
// HandleAPICreateApp returns a handler that creates a new app.
func (h *Handlers) HandleAPICreateApp() http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) { return func(writer http.ResponseWriter, request *http.Request) {
var req createRequest var req apiCreateRequest
decodeErr := json.NewDecoder(request.Body).Decode(&req) decodeErr := json.NewDecoder(request.Body).Decode(&req)
if decodeErr != nil { if decodeErr != nil {
@ -200,27 +221,9 @@ func (h *Handlers) HandleAPICreateApp() http.HandlerFunc {
return return
} }
if req.Name == "" || req.RepoURL == "" { if errMsg := validateCreateRequest(&req); errMsg != "" {
h.respondJSON(writer, request, h.respondJSON(writer, request,
map[string]string{"error": "name and repo_url are required"}, map[string]string{"error": errMsg},
http.StatusBadRequest)
return
}
nameErr := validateAppName(req.Name)
if nameErr != nil {
h.respondJSON(writer, request,
map[string]string{"error": "invalid app name: " + nameErr.Error()},
http.StatusBadRequest)
return
}
repoURLErr := validateRepoURL(req.RepoURL)
if repoURLErr != nil {
h.respondJSON(writer, request,
map[string]string{"error": "invalid repository URL: " + repoURLErr.Error()},
http.StatusBadRequest) http.StatusBadRequest)
return return

View File

@ -0,0 +1,6 @@
package handlers
// ValidateRepoURLForTest exports validateRepoURL for testing.
func ValidateRepoURLForTest(repoURL string) error {
return validateRepoURL(repoURL)
}

View File

@ -780,6 +780,7 @@ func TestHandleVolumeAddValidatesPaths(t *testing.T) {
// Check if volume was created by listing volumes // Check if volume was created by listing volumes
volumes, _ := createdApp.GetVolumes(context.Background()) volumes, _ := createdApp.GetVolumes(context.Background())
found := false found := false
for _, v := range volumes { for _, v := range volumes {
if v.HostPath == tt.hostPath && v.ContainerPath == tt.containerPath { if v.HostPath == tt.hostPath && v.ContainerPath == tt.containerPath {
found = true found = true

View File

@ -20,6 +20,16 @@ var (
// Only the "git" user is allowed, as that is the standard for SSH deploy keys. // Only the "git" user is allowed, as that is the standard for SSH deploy keys.
var scpLikeRepoRe = regexp.MustCompile(`^git@[a-zA-Z0-9._-]+:.+$`) var scpLikeRepoRe = regexp.MustCompile(`^git@[a-zA-Z0-9._-]+:.+$`)
// allowedRepoSchemes lists the URL schemes accepted for repository URLs.
//
//nolint:gochecknoglobals // package-level constant map parsed once
var allowedRepoSchemes = map[string]bool{
"https": true,
"http": true,
"ssh": true,
"git": true,
}
// validateRepoURL checks that the given repository URL is valid and uses an allowed scheme. // validateRepoURL checks that the given repository URL is valid and uses an allowed scheme.
func validateRepoURL(repoURL string) error { func validateRepoURL(repoURL string) error {
if strings.TrimSpace(repoURL) == "" { if strings.TrimSpace(repoURL) == "" {
@ -41,17 +51,17 @@ func validateRepoURL(repoURL string) error {
return errRepoURLScheme return errRepoURLScheme
} }
// Parse as standard URL return validateParsedRepoURL(repoURL)
}
// validateParsedRepoURL validates a standard URL-format repository URL.
func validateParsedRepoURL(repoURL string) error {
parsed, err := url.Parse(repoURL) parsed, err := url.Parse(repoURL)
if err != nil { if err != nil {
return errRepoURLInvalid return errRepoURLInvalid
} }
// Must have a recognized scheme if !allowedRepoSchemes[strings.ToLower(parsed.Scheme)] {
switch strings.ToLower(parsed.Scheme) {
case "https", "http", "ssh", "git":
// OK
default:
return errRepoURLInvalid return errRepoURLInvalid
} }

View File

@ -1,6 +1,10 @@
package handlers package handlers_test
import "testing" import (
"testing"
"git.eeqj.de/sneak/upaas/internal/handlers"
)
func TestValidateRepoURL(t *testing.T) { func TestValidateRepoURL(t *testing.T) {
t.Parallel() t.Parallel()
@ -43,13 +47,13 @@ func TestValidateRepoURL(t *testing.T) {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
t.Parallel() t.Parallel()
err := validateRepoURL(tc.url) err := handlers.ValidateRepoURLForTest(tc.url)
if tc.wantErr && err == nil { if tc.wantErr && err == nil {
t.Errorf("validateRepoURL(%q) = nil, want error", tc.url) t.Errorf("ValidateRepoURLForTest(%q) = nil, want error", tc.url)
} }
if !tc.wantErr && err != nil { if !tc.wantErr && err != nil {
t.Errorf("validateRepoURL(%q) = %v, want nil", tc.url, err) t.Errorf("ValidateRepoURLForTest(%q) = %v, want nil", tc.url, err)
} }
}) })
} }