feat: Add audit logging (#38189)

Co-authored-by: bircni <bircni@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
bircni
2026-09-12 10:15:23 +02:00
committed by GitHub
parent 4d43445532
commit da37b7916b
136 changed files with 3864 additions and 209 deletions
+11 -2
View File
@@ -15,6 +15,7 @@ import (
"gitea.dev/routers/api/v1/shared"
"gitea.dev/routers/api/v1/utils"
actions_service "gitea.dev/services/actions"
"gitea.dev/services/audit"
"gitea.dev/services/context"
secret_service "gitea.dev/services/secrets"
)
@@ -50,12 +51,18 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
opt := web.GetForm[*api.CreateOrUpdateSecretOption](ctx)
_, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description)
s, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description)
if err != nil {
ctx.APIErrorAuto(err)
return
}
actions := audit.SecretUpdate
if created {
actions = audit.SecretAdd
}
audit.RecordScoped(ctx, ctx.Doer, nil, actions, "secret", s.Name)
if created {
ctx.Status(http.StatusCreated)
} else {
@@ -86,12 +93,14 @@ func DeleteSecret(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
err := secret_service.DeleteSecretByName(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"))
s, err := secret_service.DeleteSecretByName(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"))
if err != nil {
ctx.APIErrorAuto(err)
return
}
audit.RecordScoped(ctx, ctx.Doer, nil, audit.SecretRemove, "secret", s.Name)
ctx.Status(http.StatusNoContent)
}
+29 -1
View File
@@ -10,11 +10,13 @@ import (
"strconv"
"strings"
audit_model "gitea.dev/models/audit"
auth_model "gitea.dev/models/auth"
"gitea.dev/models/db"
api "gitea.dev/modules/structs"
"gitea.dev/modules/web"
"gitea.dev/routers/api/v1/utils"
"gitea.dev/services/audit"
"gitea.dev/services/context"
"gitea.dev/services/convert"
"gitea.dev/services/forms"
@@ -149,6 +151,9 @@ func CreateAccessToken(ctx *context.APIContext) {
ctx.APIErrorInternal(err)
return
}
audit.Record(ctx, audit_model.UserAccessTokenAdd, ctx.ContextUser, "token", t.Name, "token_scope", t.Scope)
ctx.JSON(http.StatusCreated, &api.AccessToken{
Name: t.Name,
Token: t.Token,
@@ -211,11 +216,19 @@ func DeleteAccessToken(ctx *context.APIContext) {
}
}
if err := auth_model.DeleteAccessTokenByID(ctx, tokenID, ctx.ContextUser.ID); err != nil {
t, err := auth_model.GetAccessTokenByID(ctx, tokenID, ctx.ContextUser.ID)
if err != nil {
ctx.APIErrorAuto(err)
return
}
if err := auth_model.DeleteAccessTokenByID(ctx, t.ID, ctx.ContextUser.ID); err != nil {
ctx.APIErrorAuto(err)
return
}
audit.Record(ctx, audit_model.UserAccessTokenRemove, ctx.ContextUser, "token", t.Name)
ctx.Status(http.StatusNoContent)
}
@@ -261,6 +274,8 @@ func CreateOauth2Application(ctx *context.APIContext) {
}
app.ClientSecret = secret
audit.Record(ctx, audit_model.UserOAuth2ApplicationAdd, ctx.Doer, "oauth2_application", app.Name)
ctx.JSON(http.StatusCreated, convert.ToOAuth2Application(app))
}
@@ -323,6 +338,15 @@ func DeleteOauth2Application(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
appID := ctx.PathParamInt64("id")
app, err := auth_model.GetOAuth2ApplicationByID(ctx, appID)
if err != nil {
if auth_model.IsErrOAuthApplicationNotFound(err) {
ctx.APIErrorNotFound()
} else {
ctx.APIErrorInternal(err)
}
return
}
if err := auth_model.DeleteOAuth2Application(ctx, appID, ctx.Doer.ID); err != nil {
if auth_model.IsErrOAuthApplicationNotFound(err) {
ctx.APIErrorNotFound()
@@ -332,6 +356,8 @@ func DeleteOauth2Application(ctx *context.APIContext) {
return
}
audit.Record(ctx, audit_model.UserOAuth2ApplicationRemove, ctx.Doer, "oauth2_application", app.Name)
ctx.Status(http.StatusNoContent)
}
@@ -430,5 +456,7 @@ func UpdateOauth2Application(ctx *context.APIContext) {
return
}
audit.Record(ctx, audit_model.UserOAuth2ApplicationUpdate, ctx.Doer, "oauth2_application", app.Name)
ctx.JSON(http.StatusOK, convert.ToOAuth2Application(app))
}