mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50:12 +00:00
feat(agentcompat): expose dashboard capability routes
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
//go:build agentcompat
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
"github.com/nezhahq/nezha/service/rpc"
|
||||
"github.com/nezhahq/nezha/service/singleton"
|
||||
)
|
||||
|
||||
func TestAgentcompatNATCapabilityUsesExactCurrentProfilePermission(t *testing.T) {
|
||||
cleanup, userID := setupMCPTest(t)
|
||||
t.Cleanup(cleanup)
|
||||
handler := rpc.NewNezhaHandler()
|
||||
originalHandler := rpc.NezhaHandlerSingleton
|
||||
originalNAT := singleton.NATShared
|
||||
rpc.NezhaHandlerSingleton = handler
|
||||
t.Cleanup(func() {
|
||||
rpc.NezhaHandlerSingleton = originalHandler
|
||||
singleton.NATShared = originalNAT
|
||||
})
|
||||
require.NoError(t, singleton.DB.AutoMigrate(&model.NAT{}))
|
||||
secondServer := &model.Server{Common: model.Common{ID: 8}}
|
||||
secondServer.SetUserID(userID)
|
||||
singleton.ServerShared.InsertForTest(secondServer)
|
||||
profile := &model.NAT{Common: model.Common{ID: 41, UserID: userID}, Name: "private-profile", ServerID: 7, Domain: "private-profile.example"}
|
||||
foreignProfile := &model.NAT{Common: model.Common{ID: 42, UserID: 999}, Name: "foreign-profile", ServerID: 7, Domain: "foreign-profile.example"}
|
||||
require.NoError(t, singleton.DB.Create(profile).Error)
|
||||
require.NoError(t, singleton.DB.Create(foreignProfile).Error)
|
||||
singleton.NATShared = singleton.NewNATClass()
|
||||
token, plaintext := mkToken(t, userID, []string{model.ScopeNATRead}, []uint64{7, 8})
|
||||
server := newAgentcompatCapabilityServer(t)
|
||||
|
||||
capability := registerAgentcompatCapability(t, server.URL, plaintext, agentcompatCapabilityRegisterRequest{Purpose: "nat", ServerID: 7, ResourceID: 41})
|
||||
status, mismatchBody := postAgentcompatEmpty(t, server.URL+agentcompatCapabilityRegisterPath, plaintext, agentcompatCapabilityRegisterRequest{Purpose: "nat", ServerID: 8, ResourceID: 41})
|
||||
require.Equal(t, http.StatusOK, status)
|
||||
require.Contains(t, mismatchBody, errAgentcompatCapabilityUnavailable.Error())
|
||||
foreignStatus, foreignBody := postAgentcompatEmpty(t, server.URL+agentcompatCapabilityRegisterPath, plaintext, agentcompatCapabilityRegisterRequest{Purpose: "nat", ServerID: 7, ResourceID: 42})
|
||||
require.Equal(t, http.StatusOK, foreignStatus)
|
||||
require.Contains(t, foreignBody, errAgentcompatCapabilityUnavailable.Error())
|
||||
|
||||
parsed, err := rpc.ParseAgentCompatIOStreamCapability(capability)
|
||||
require.NoError(t, err)
|
||||
access := rpc.AgentCompatCapabilityAccess{
|
||||
Capability: parsed, Owner: rpc.AgentCompatCapabilityOwner{PATID: token.ID, UserID: userID},
|
||||
Purpose: rpc.AgentCompatCapabilityNAT, TargetServerID: 7, ResourceID: 41, ServerAccessAllowed: true,
|
||||
}
|
||||
handle, err := handler.ConsumeAgentCompatNATCapability(access)
|
||||
require.NoError(t, err)
|
||||
lease, err := handler.CreateAgentCompatNATStream(handle, "private-nat-stream")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { require.NoError(t, handler.CloseAgentCompatNATStreamLease(lease)) })
|
||||
require.NoError(t, handler.PublishAgentCompatNATStream(handle, rpc.AgentCompatNATPublication{Purpose: rpc.AgentCompatCapabilityNAT, TargetServerID: 7, ResourceID: 41, StreamID: "private-nat-stream"}))
|
||||
|
||||
profile.ServerID = 8
|
||||
singleton.NATShared.Update(profile)
|
||||
_, unavailableErr := postAgentcompatCapability[agentcompatCapabilityWaitRequest, agentcompatCapabilityWaitResponse](context.Background(), server.URL+agentcompatCapabilityWaitPath, plaintext, agentcompatCapabilityWaitRequest{Capability: capability, Purpose: "nat", ServerID: 7, ResourceID: 41})
|
||||
require.Error(t, unavailableErr)
|
||||
require.NotContains(t, unavailableErr.Error(), capability)
|
||||
require.NotContains(t, unavailableErr.Error(), "private-nat-stream")
|
||||
profile.ServerID = 7
|
||||
singleton.NATShared.Update(profile)
|
||||
waitContext, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
waited, err := postAgentcompatCapability[agentcompatCapabilityWaitRequest, agentcompatCapabilityWaitResponse](waitContext, server.URL+agentcompatCapabilityWaitPath, plaintext, agentcompatCapabilityWaitRequest{Capability: capability, Purpose: "nat", ServerID: 7, ResourceID: 41})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "private-nat-stream", waited.StreamID)
|
||||
}
|
||||
|
||||
func TestAgentcompatCapabilityOwnerIncludesCurrentAdminRole(t *testing.T) {
|
||||
cleanup, _ := setupMCPTest(t)
|
||||
t.Cleanup(cleanup)
|
||||
handler := rpc.NewNezhaHandler()
|
||||
originalHandler := rpc.NezhaHandlerSingleton
|
||||
rpc.NezhaHandlerSingleton = handler
|
||||
t.Cleanup(func() { rpc.NezhaHandlerSingleton = originalHandler })
|
||||
admin := &model.User{Common: model.Common{ID: 300}, Username: "cap-admin", Role: model.RoleAdmin}
|
||||
require.NoError(t, singleton.DB.Create(admin).Error)
|
||||
target := &model.Server{Common: model.Common{ID: 8}}
|
||||
target.SetUserID(999)
|
||||
singleton.ServerShared.InsertForTest(target)
|
||||
token, plaintext := mkDistinctCapabilityToken(t, admin.ID, "admin")
|
||||
token.SetServerIDs([]uint64{8})
|
||||
require.NoError(t, singleton.DB.Model(token).Update("servers_csv", token.ServersCSV).Error)
|
||||
server := newAgentcompatCapabilityServer(t)
|
||||
capability := registerAgentcompatCapability(t, server.URL, plaintext, agentcompatCapabilityRegisterRequest{Purpose: "terminal", ServerID: 8})
|
||||
parsed, err := rpc.ParseAgentCompatIOStreamCapability(capability)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, handler.CreateStreamWithPurpose("admin-private-stream", admin.ID, 8, rpc.PurposeTerminal))
|
||||
require.NoError(t, handler.BindAgentCompatIOStreamCapability(rpc.AgentCompatCapabilityBinding{
|
||||
AgentCompatCapabilityAccess: rpc.AgentCompatCapabilityAccess{
|
||||
Capability: parsed, Owner: rpc.AgentCompatCapabilityOwner{PATID: token.ID, UserID: admin.ID, IsAdmin: true},
|
||||
Purpose: rpc.AgentCompatCapabilityTerminal, TargetServerID: 8, ServerAccessAllowed: true,
|
||||
},
|
||||
StreamID: "admin-private-stream",
|
||||
}))
|
||||
waitContext, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
waited, err := postAgentcompatCapability[agentcompatCapabilityWaitRequest, agentcompatCapabilityWaitResponse](waitContext, server.URL+agentcompatCapabilityWaitPath, plaintext, agentcompatCapabilityWaitRequest{Capability: capability, Purpose: "terminal", ServerID: 8})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "admin-private-stream", waited.StreamID)
|
||||
}
|
||||
Reference in New Issue
Block a user