feat: 加固 Agent CLI 执行边界并更新模型目录
收紧 SSH 命令护栏、权限校验与远程执行会话,并同步主流大模型供应商列表。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
67660ae1d6
commit
2fd1624bec
18 files changed
+480
-49
No files matched your search
@@ -146,6 +146,29 @@ func AdminAuth() gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// PermissionAuth 校验当前用户是否拥有指定权限码,管理员直接放行。 // Logan.Li
|
||||
func PermissionAuth(db *gorm.DB, permissionCode string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if GetIsAdmin(c) {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
var count int64
|
||||
err := db.Table("iam_user_roles ur").
|
||||
Joins("JOIN iam_roles r ON r.id = ur.role_id AND r.status = 1").
|
||||
Joins("JOIN iam_role_permissions rp ON rp.role_id = r.id").
|
||||
Joins("JOIN iam_permissions p ON p.id = rp.permission_id AND p.status = 1").
|
||||
Where("ur.user_id = ? AND p.code = ?", GetUserID(c), permissionCode).
|
||||
Count(&count).Error
|
||||
if err != nil || count == 0 {
|
||||
c.JSON(http.StatusForbidden, model.Response{Code: 403, Message: "无此功能权限"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserID 获取当前用户ID
|
||||
func GetUserID(c *gin.Context) uint {
|
||||
userID, exists := c.Get("userID")
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestPermissionAuth(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("打开测试数据库失败: %v", err)
|
||||
}
|
||||
statements := []string{
|
||||
"CREATE TABLE iam_user_roles (user_id INTEGER, role_id INTEGER)",
|
||||
"CREATE TABLE iam_roles (id INTEGER PRIMARY KEY, status INTEGER)",
|
||||
"CREATE TABLE iam_role_permissions (role_id INTEGER, permission_id INTEGER)",
|
||||
"CREATE TABLE iam_permissions (id INTEGER PRIMARY KEY, code TEXT, status INTEGER)",
|
||||
"INSERT INTO iam_user_roles(user_id, role_id) VALUES (7, 1)",
|
||||
"INSERT INTO iam_roles(id, status) VALUES (1, 1)",
|
||||
"INSERT INTO iam_role_permissions(role_id, permission_id) VALUES (1, 10)",
|
||||
"INSERT INTO iam_permissions(id, code, status) VALUES (10, 'aiops:agent-cli', 1)",
|
||||
}
|
||||
for _, statement := range statements {
|
||||
if err := db.Exec(statement).Error; err != nil {
|
||||
t.Fatalf("准备测试数据失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
userID uint
|
||||
isAdmin bool
|
||||
wantStatus int
|
||||
}{
|
||||
{name: "granted", userID: 7, wantStatus: http.StatusNoContent},
|
||||
{name: "denied", userID: 8, wantStatus: http.StatusForbidden},
|
||||
{name: "admin", userID: 9, isAdmin: true, wantStatus: http.StatusNoContent},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
router := gin.New()
|
||||
router.Use(func(c *gin.Context) {
|
||||
c.Set("userID", tc.userID)
|
||||
c.Set("isAdmin", tc.isAdmin)
|
||||
})
|
||||
router.GET("/agent", PermissionAuth(db, "aiops:agent-cli"), func(c *gin.Context) {
|
||||
c.Status(http.StatusNoContent)
|
||||
})
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/agent", nil))
|
||||
if recorder.Code != tc.wantStatus {
|
||||
t.Fatalf("状态码=%d, want %d, body=%s", recorder.Code, tc.wantStatus, recorder.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user