2
0

feat(routes): add vault token authentication fallback for secret APIs
Some checks failed
Build and Release / Lint (push) Has been cancelled
Build and Release / Tests (push) Has been cancelled
Build and Release / Create Release (push) Has been cancelled

Implements dual authentication strategy for secret management endpoints (PUT, restore, list versions, rollback). When Gitea user authentication is not available, the system now falls back to vault token authentication. This enables both user-based and token-based access patterns.

Changes include:
- Add Comment field to CreateSecretRequest for update operations
- Replace requireRepoWrite helper with inline auth checks
- Support userID=0 for token-based operations
- Apply consistent auth pattern across all affected endpoints
This commit is contained in:
2026-01-23 02:27:38 -05:00
parent d5beb9fc73
commit d9e0936089

View File

@@ -117,6 +117,7 @@ type CreateSecretRequest struct {
Description string `json:"description"`
Type string `json:"type"`
Value string `json:"value" binding:"required"`
Comment string `json:"comment"` // Used when updating existing secret
}
// UpdateSecretRequest is the request body for updating a secret
@@ -496,8 +497,29 @@ func apiPutSecret(lic *license.Manager) http.HandlerFunc {
return
}
if !requireRepoWrite(ctx) {
return
// Try Gitea user auth first, then fall back to vault token auth
var userID int64
if ctx.Doer != nil {
// Gitea user - check write permission
if !ctx.Repo.CanWrite(unit.TypeCode) {
ctx.JSON(http.StatusForbidden, map[string]any{
"error": "forbidden",
"message": "Repository write access required",
})
return
}
userID = ctx.Doer.ID
} else {
// Try vault token auth with write requirement
authResult := authenticateVaultToken(ctx, r, true)
if !authResult.Success {
ctx.JSON(http.StatusUnauthorized, map[string]any{
"error": "unauthorized",
"message": authResult.Error,
})
return
}
userID = 0 // Token-based access
}
name := chi.URLParam(r, "name")
@@ -569,8 +591,8 @@ func apiPutSecret(lic *license.Manager) http.HandlerFunc {
secret, err := services.UpdateSecret(ctx, ctx.Repo.Repository.ID, name, services.UpdateSecretOptions{
Type: secretType,
Value: req.Value,
Comment: req.Description,
UpdaterID: ctx.Doer.ID,
Comment: req.Comment,
UpdaterID: userID,
})
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]any{
@@ -651,8 +673,24 @@ func apiRestoreSecret(lic *license.Manager) http.HandlerFunc {
return
}
if !requireRepoWrite(ctx) {
return
// Try Gitea user auth first, then fall back to vault token auth
if ctx.Doer != nil {
if !ctx.Repo.CanWrite(unit.TypeCode) {
ctx.JSON(http.StatusForbidden, map[string]any{
"error": "forbidden",
"message": "Repository write access required",
})
return
}
} else {
authResult := authenticateVaultToken(ctx, r, true)
if !authResult.Success {
ctx.JSON(http.StatusUnauthorized, map[string]any{
"error": "unauthorized",
"message": authResult.Error,
})
return
}
}
name := chi.URLParam(r, "name")
@@ -690,6 +728,18 @@ func apiListVersions(lic *license.Manager) http.HandlerFunc {
return
}
// Try Gitea user auth first, then fall back to vault token auth
if ctx.Doer == nil {
authResult := authenticateVaultToken(ctx, r, false)
if !authResult.Success {
ctx.JSON(http.StatusUnauthorized, map[string]any{
"error": "unauthorized",
"message": authResult.Error,
})
return
}
}
name := chi.URLParam(r, "name")
versions, err := services.ListVersions(ctx, ctx.Repo.Repository.ID, name)
@@ -734,8 +784,27 @@ func apiRollbackSecret(lic *license.Manager) http.HandlerFunc {
return
}
if !requireRepoWrite(ctx) {
return
// Try Gitea user auth first, then fall back to vault token auth
var userID int64
if ctx.Doer != nil {
if !ctx.Repo.CanWrite(unit.TypeCode) {
ctx.JSON(http.StatusForbidden, map[string]any{
"error": "forbidden",
"message": "Repository write access required",
})
return
}
userID = ctx.Doer.ID
} else {
authResult := authenticateVaultToken(ctx, r, true)
if !authResult.Success {
ctx.JSON(http.StatusUnauthorized, map[string]any{
"error": "unauthorized",
"message": authResult.Error,
})
return
}
userID = 0
}
name := chi.URLParam(r, "name")
@@ -757,7 +826,7 @@ func apiRollbackSecret(lic *license.Manager) http.HandlerFunc {
return
}
if err := services.RollbackSecret(ctx, ctx.Repo.Repository.ID, name, req.Version, ctx.Doer.ID); err != nil {
if err := services.RollbackSecret(ctx, ctx.Repo.Repository.ID, name, req.Version, userID); err != nil {
switch err {
case services.ErrSecretNotFound:
ctx.JSON(http.StatusNotFound, map[string]any{