enhance: Improve validation errors for secrets/variables (#39221)

Signed-off-by: Ross Golder <ross@golder.org>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Ross Golder
2026-09-04 00:28:58 +00:00
committed by GitHub
co-authored by wxiaoguang
parent ce2fd8d882
commit 2d3ad4a530
19 changed files with 148 additions and 218 deletions
+4 -15
View File
@@ -170,22 +170,11 @@ func (ctx *APIContext) APIError(status int, msg string) {
// APIErrorAuto use error check function to determine the response code
func (ctx *APIContext) APIErrorAuto(err error) {
switch {
case errors.Is(err, util.ErrInvalidArgument):
ctx.APIError(http.StatusBadRequest, err.Error())
case errors.Is(err, util.ErrPermissionDenied):
ctx.APIError(http.StatusForbidden, err.Error())
case errors.Is(err, util.ErrNotExist):
ctx.APIError(http.StatusNotFound, err.Error())
case errors.Is(err, util.ErrAlreadyExist):
ctx.APIError(http.StatusConflict, err.Error())
case errors.Is(err, util.ErrContentTooLarge):
ctx.APIError(http.StatusRequestEntityTooLarge, err.Error())
case errors.Is(err, util.ErrUnprocessableContent):
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
default:
ctx.apiErrorInternal(1, err)
if errMsg, code := util.ErrorUnwrapForUser(err); errMsg != "" {
ctx.APIError(code, errMsg)
return
}
ctx.apiErrorInternal(1, err)
}
type apiContextKeyType struct{}
+20 -4
View File
@@ -18,6 +18,7 @@ import (
"gitea.dev/modules/cache"
"gitea.dev/modules/httpcache"
"gitea.dev/modules/httplib"
"gitea.dev/modules/log"
"gitea.dev/modules/reqctx"
"gitea.dev/modules/session"
"gitea.dev/modules/setting"
@@ -245,8 +246,8 @@ func (ctx *Context) JSONOK() {
ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
}
func buildJsonErrorMap(msg any) map[string]any {
switch v := msg.(type) {
func buildJsonErrorMap[T string | template.HTML](msg T) map[string]any {
switch v := any(msg).(type) {
case string:
return map[string]any{"errorMessage": v, "renderFormat": "text"}
case template.HTML:
@@ -255,11 +256,26 @@ func buildJsonErrorMap(msg any) map[string]any {
panic(fmt.Sprintf("unsupported type: %T", msg))
}
func (ctx *Context) JSONError(msg any) {
func (ctx *Context) JSONErrorAuto(err error) {
if errTr := util.ErrorAsTranslatable(err); errTr != nil {
msg := errTr.Translate(ctx.Locale)
ctx.JSON(http.StatusBadRequest, buildJsonErrorMap(msg))
return
}
errMsg, httpCode := util.ErrorUnwrapForUser(err)
if errMsg != "" {
ctx.JSON(httpCode, buildJsonErrorMap(errMsg))
return
}
log.ErrorWithSkip(1, "JSONErrorAuto: server internal error: %v", err)
ctx.JSON(http.StatusInternalServerError, buildJsonErrorMap(ctx.Locale.TrString("error.occurred")))
}
func (ctx *Context) JSONError[T string | template.HTML](msg T) {
ctx.JSON(http.StatusBadRequest, buildJsonErrorMap(msg))
}
func (ctx *Context) JSONErrorWithField(msg any, field string) {
func (ctx *Context) JSONErrorWithField[T string | template.HTML](msg T, field string) {
m := buildJsonErrorMap(msg)
m["errorFields"] = []string{field}
ctx.JSON(http.StatusBadRequest, m)
+5
View File
@@ -15,6 +15,7 @@ import (
"gitea.dev/modules/log"
"gitea.dev/modules/reqctx"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
"gitea.dev/services/context"
)
@@ -33,6 +34,10 @@ func (err ErrFileTypeForbidden) Error() string {
return "This file cannot be uploaded or modified due to a forbidden file extension or type."
}
func (err ErrFileTypeForbidden) Unwrap() error {
return util.ErrInvalidArgument
}
var wildcardTypeRe = regexp.MustCompile(`^[a-z]+/\*$`)
// Verify validates whether a file is allowed to be uploaded. If buf is empty, it will just check if the file