MM-24847 MM-24484 MM-24850 MM-24849 - local mode for commands (#14571)

* add unix socket listener for mmctl local mode

* First working PoC

* Adds the channel list endpoint

* Add team list endpoint

* Add a LocalClient to the api test helper and start local mode

* Add helper to test with both SystemAdmin and Local clients

* Add some docs

* Adds TestForAllClients test helper

* Incorporating @ashishbhate's proposal for adding test names to the helpers

* [MM-24146] Add unix socket listener for mmctl local mode (#14296)

* add unix socket listener for mmctl local mode

* add a constant for local-mode socket path

* reflect review comments

* Fix init errors after merge

* Adds create channel tests

* Always init local mode to allow for enabling-disabling it via config

* Check the RemoteAddr of the request before marking session as local

* Mark the request as errored if it's local and the origin is remote

* Set the socket permissions to read/write when initialising

* Fix linter

* Replace RemoteAddr check to ditch connections with the IP:PORT shape

* added update/move/get/delete command in local mode

* merge fix

* .

Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Co-authored-by: Miguel de la Cruz <miguel@mcrx.me>
Этот коммит содержится в:
Eli Yukelzon
2020-05-31 17:57:04 +03:00
коммит произвёл GitHub
родитель d1788cab85
Коммит 2af00f73c0
4 изменённых файлов: 88 добавлений и 82 удалений

Просмотреть файл

@@ -283,6 +283,7 @@ func InitLocal(configservice configservice.ConfigService, globalOptionsFunc app.
api.BaseRoutes.Plugin = api.BaseRoutes.Plugins.PathPrefix("/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
api.BaseRoutes.Commands = api.BaseRoutes.ApiRoot.PathPrefix("/commands").Subrouter()
api.BaseRoutes.Command = api.BaseRoutes.Commands.PathPrefix("/{command_id:[A-Za-z0-9]+}").Subrouter()
api.BaseRoutes.License = api.BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter()

Просмотреть файл

@@ -13,6 +13,11 @@ import (
func (api *API) InitCommandLocal() {
api.BaseRoutes.Commands.Handle("", api.ApiLocal(localCreateCommand)).Methods("POST")
api.BaseRoutes.Commands.Handle("", api.ApiLocal(listCommands)).Methods("GET")
api.BaseRoutes.Command.Handle("", api.ApiLocal(getCommand)).Methods("GET")
api.BaseRoutes.Command.Handle("", api.ApiLocal(updateCommand)).Methods("PUT")
api.BaseRoutes.Command.Handle("/move", api.ApiLocal(moveCommand)).Methods("PUT")
api.BaseRoutes.Command.Handle("", api.ApiLocal(deleteCommand)).Methods("DELETE")
}
func localCreateCommand(c *Context, w http.ResponseWriter, r *http.Request) {

Просмотреть файл

@@ -77,7 +77,6 @@ func TestCreateCommand(t *testing.T) {
func TestUpdateCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.BasicTeam
@@ -107,7 +106,8 @@ func TestUpdateCommand(t *testing.T) {
Token: "tokenchange",
}
rcmd, resp := Client.UpdateCommand(cmd2)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
rcmd, resp := client.UpdateCommand(cmd2)
CheckNoError(t, resp)
require.Equal(t, cmd2.Trigger, rcmd.Trigger, "Trigger should have updated")
@@ -122,36 +122,35 @@ func TestUpdateCommand(t *testing.T) {
cmd2.Id = GenerateTestId()
rcmd, resp = Client.UpdateCommand(cmd2)
rcmd, resp = client.UpdateCommand(cmd2)
CheckNotFoundStatus(t, resp)
require.Nil(t, rcmd, "should be empty")
cmd2.Id = "junk"
_, resp = Client.UpdateCommand(cmd2)
_, resp = client.UpdateCommand(cmd2)
CheckBadRequestStatus(t, resp)
cmd2.Id = cmd1.Id
cmd2.TeamId = GenerateTestId()
_, resp = Client.UpdateCommand(cmd2)
_, resp = client.UpdateCommand(cmd2)
CheckBadRequestStatus(t, resp)
cmd2.TeamId = team.Id
_, resp = th.Client.UpdateCommand(cmd2)
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.UpdateCommand(cmd2)
})
th.SystemAdminClient.Logout()
_, resp := th.SystemAdminClient.UpdateCommand(cmd2)
CheckUnauthorizedStatus(t, resp)
}
func TestMoveCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.BasicTeam
newTeam := th.CreateTeam()
@@ -171,8 +170,9 @@ func TestMoveCommand(t *testing.T) {
}
rcmd1, _ := th.App.CreateCommand(cmd1)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
ok, resp := Client.MoveCommand(newTeam.Id, rcmd1.Id)
ok, resp := client.MoveCommand(newTeam.Id, rcmd1.Id)
CheckNoError(t, resp)
require.True(t, ok)
@@ -180,14 +180,14 @@ func TestMoveCommand(t *testing.T) {
require.NotNil(t, rcmd1)
require.Equal(t, newTeam.Id, rcmd1.TeamId)
ok, resp = Client.MoveCommand(newTeam.Id, "bogus")
ok, resp = client.MoveCommand(newTeam.Id, "bogus")
CheckBadRequestStatus(t, resp)
require.False(t, ok)
ok, resp = Client.MoveCommand(GenerateTestId(), rcmd1.Id)
ok, resp = client.MoveCommand(GenerateTestId(), rcmd1.Id)
CheckNotFoundStatus(t, resp)
require.False(t, ok)
})
cmd2 := &model.Command{
CreatorId: user.Id,
TeamId: team.Id,
@@ -198,18 +198,17 @@ func TestMoveCommand(t *testing.T) {
rcmd2, _ := th.App.CreateCommand(cmd2)
_, resp = th.Client.MoveCommand(newTeam.Id, rcmd2.Id)
_, resp := th.Client.MoveCommand(newTeam.Id, rcmd2.Id)
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.MoveCommand(newTeam.Id, rcmd2.Id)
th.SystemAdminClient.Logout()
_, resp = th.SystemAdminClient.MoveCommand(newTeam.Id, rcmd2.Id)
CheckUnauthorizedStatus(t, resp)
}
func TestDeleteCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.BasicTeam
@@ -227,9 +226,11 @@ func TestDeleteCommand(t *testing.T) {
Trigger: "trigger1",
}
rcmd1, _ := th.App.CreateCommand(cmd1)
ok, resp := Client.DeleteCommand(rcmd1.Id)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
cmd1.Id = ""
rcmd1, err := th.App.CreateCommand(cmd1)
require.Nil(t, err)
ok, resp := client.DeleteCommand(rcmd1.Id)
CheckNoError(t, resp)
require.True(t, ok)
@@ -237,14 +238,14 @@ func TestDeleteCommand(t *testing.T) {
rcmd1, _ = th.App.GetCommand(rcmd1.Id)
require.Nil(t, rcmd1)
ok, resp = Client.DeleteCommand("junk")
ok, resp = client.DeleteCommand("junk")
CheckBadRequestStatus(t, resp)
require.False(t, ok)
_, resp = Client.DeleteCommand(GenerateTestId())
_, resp = client.DeleteCommand(GenerateTestId())
CheckNotFoundStatus(t, resp)
})
cmd2 := &model.Command{
CreatorId: user.Id,
TeamId: team.Id,
@@ -255,11 +256,11 @@ func TestDeleteCommand(t *testing.T) {
rcmd2, _ := th.App.CreateCommand(cmd2)
_, resp = th.Client.DeleteCommand(rcmd2.Id)
_, resp := th.Client.DeleteCommand(rcmd2.Id)
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.DeleteCommand(rcmd2.Id)
th.SystemAdminClient.Logout()
_, resp = th.SystemAdminClient.DeleteCommand(rcmd2.Id)
CheckUnauthorizedStatus(t, resp)
}
@@ -513,7 +514,6 @@ func TestListCommandAutocompleteSuggestions(t *testing.T) {
func TestGetCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.Client
enableCommands := *th.App.Config().ServiceSettings.EnableCommands
defer func() {
@@ -530,9 +530,10 @@ func TestGetCommand(t *testing.T) {
newCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
CheckNoError(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
t.Run("ValidId", func(t *testing.T) {
cmd, resp := th.SystemAdminClient.GetCommandById(newCmd.Id)
cmd, resp := client.GetCommandById(newCmd.Id)
CheckNoError(t, resp)
require.Equal(t, newCmd.Id, cmd.Id)
@@ -544,27 +545,27 @@ func TestGetCommand(t *testing.T) {
})
t.Run("InvalidId", func(t *testing.T) {
_, resp := th.SystemAdminClient.GetCommandById(strings.Repeat("z", len(newCmd.Id)))
_, resp := client.GetCommandById(strings.Repeat("z", len(newCmd.Id)))
require.Error(t, resp.Error)
})
})
t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) {
_, resp := Client.GetCommandById(newCmd.Id)
_, resp := th.Client.GetCommandById(newCmd.Id)
CheckNotFoundStatus(t, resp)
})
t.Run("NoMember", func(t *testing.T) {
Client.Logout()
th.Client.Logout()
user := th.CreateUser()
th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
Client.Login(user.Email, user.Password)
_, resp := Client.GetCommandById(newCmd.Id)
th.Client.Login(user.Email, user.Password)
_, resp := th.Client.GetCommandById(newCmd.Id)
CheckNotFoundStatus(t, resp)
})
t.Run("NotLoggedIn", func(t *testing.T) {
Client.Logout()
_, resp := Client.GetCommandById(newCmd.Id)
th.Client.Logout()
_, resp := th.Client.GetCommandById(newCmd.Id)
CheckUnauthorizedStatus(t, resp)
})
}

Просмотреть файл

@@ -29,7 +29,6 @@ func (a *App) SessionHasPermissionToTeam(session model.Session, teamId string, p
if session.IsUnrestricted() {
return true
}
teamMember := session.GetTeamByTeamId(teamId)
if teamMember != nil {
if a.RolesGrantPermission(teamMember.GetRoles(), permission.Id) {