@@ -4,12 +4,15 @@ import (
4
4
"context"
5
5
"fmt"
6
6
"github.com/kballard/go-shellquote"
7
+ "github.com/samber/lo"
7
8
"github.com/slack-go/slack"
8
9
"github.com/slack-go/slack/slackevents"
9
10
"github.com/slack-go/slack/socketmode"
10
11
"github.com/traPtitech/DevOpsBot/pkg/config"
11
12
"github.com/traPtitech/DevOpsBot/pkg/domain"
12
13
"go.uber.org/zap"
14
+ "log/slog"
15
+ "regexp"
13
16
"strings"
14
17
)
15
18
@@ -94,17 +97,55 @@ func (s *slackBot) handle(e socketmode.Event) error {
94
97
return nil
95
98
}
96
99
100
+ var mentionRegexp = regexp .MustCompile ("^<@(\\ w+)(?:\\ |\\ w+)?>" )
101
+
102
+ func (s * slackBot ) getExecutorID (ev * slackevents.MessageEvent ) (executorID string , commandText string , ok bool ) {
103
+ executorID = ev .User
104
+ commandText = ev .Text
105
+
106
+ if ev .BotID == "" {
107
+ // Normal execution by user
108
+ return executorID , commandText , true
109
+ }
110
+
111
+ // Execution by bots - check if they are the trusted workflow members
112
+ executorID = ev .BotID
113
+ mentionIndices := mentionRegexp .FindStringSubmatchIndex (commandText )
114
+ if ! lo .Contains (config .C .Slack .TrustedWorkflows , executorID ) {
115
+ // If they are not trusted, ignore bots
116
+ if mentionIndices != nil {
117
+ // Log bot ID as they are difficult to get from UI
118
+ slog .Info ("Skipping impersonation request from bot" , "bot_id" , executorID , "display_name" , ev .Username )
119
+ }
120
+ return "" , "" , false
121
+ }
122
+
123
+ // Check if the workflow is impersonating execution user
124
+ if mentionIndices != nil && mentionIndices [0 ] == 0 {
125
+ // Impersonate user
126
+ executorID = commandText [mentionIndices [2 ]:mentionIndices [3 ]]
127
+ // Trim the mention part
128
+ commandText = commandText [mentionIndices [1 ]:]
129
+ commandText = strings .TrimSpace (commandText )
130
+ return executorID , commandText , true
131
+ } else {
132
+ // If they are not impersonating, fallback the executor to its own ID
133
+ return executorID , commandText , true
134
+ }
135
+ }
136
+
97
137
func (s * slackBot ) handleEventsAPI (e * slackevents.EventsAPIEvent ) error {
98
138
switch ev := e .InnerEvent .Data .(type ) {
99
139
case * slackevents.MessageEvent :
100
140
// Validate command execution context
101
- if ev .BotID != "" {
102
- return nil // Ignore bots
141
+ executorID , commandText , ok := s .getExecutorID (ev )
142
+ if ! ok {
143
+ return nil // Not a valid user
103
144
}
104
145
if ev .Channel != config .C .Slack .ChannelID {
105
146
return nil // Ignore messages not from the specified channel
106
147
}
107
- if ! strings .HasPrefix (ev . Text , config .C .Prefix ) {
148
+ if ! strings .HasPrefix (commandText , config .C .Prefix ) {
108
149
return nil // Command prefix does not match
109
150
}
110
151
@@ -113,8 +154,8 @@ func (s *slackBot) handleEventsAPI(e *slackevents.EventsAPIEvent) error {
113
154
Channel : ev .Channel ,
114
155
Timestamp : ev .TimeStamp ,
115
156
}
116
- commandText : = strings .Trim (ev . Text , config .C .Prefix )
117
- return s .executeCommand (commandText , messageRef , ev . User )
157
+ commandText = strings .Trim (commandText , config .C .Prefix )
158
+ return s .executeCommand (commandText , messageRef , executorID )
118
159
default :
119
160
return nil
120
161
}
0 commit comments