Skip to content

Commit 7c4ebdb

Browse files
committed
Merge branch 'yasu/filter-out-bot-msg'
* yasu/filter-out-bot-msg: log#warn and include contextual info slack: don't unfurl own msg links slack: add auth.test endpoint with atd adapter
2 parents 28cd213 + 0332f1f commit 7c4ebdb

File tree

8 files changed

+90
-2
lines changed

8 files changed

+90
-2
lines changed

lib/action.ml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,23 @@ module Action (Github_api : Api.Github) (Slack_api : Api.Slack) = struct
238238
Lwt.return_unit
239239

240240
let process_link_shared_event (ctx : Context.t) (event : Slack_t.link_shared_event) =
241+
let fetch_bot_user_id () =
242+
match%lwt Slack_api.send_auth_test ~ctx () with
243+
| Ok { user_id; _ } ->
244+
ctx.state.bot_user_id <- Some user_id;
245+
let%lwt () =
246+
Option.value_map ctx.state_filepath ~default:Lwt.return_unit ~f:(fun path ->
247+
match%lwt State.save ctx.state path with
248+
| Ok () -> Lwt.return_unit
249+
| Error msg ->
250+
log#warn "failed to save state file %s : %s" path msg;
251+
Lwt.return_unit)
252+
in
253+
Lwt.return_some user_id
254+
| Error msg ->
255+
log#warn "failed to query slack auth.test : %s" msg;
256+
Lwt.return_none
257+
in
241258
let process link =
242259
match Github.gh_link_of_string link with
243260
| None -> Lwt.return_none
@@ -259,7 +276,14 @@ module Action (Github_api : Api.Github) (Slack_api : Api.Slack) = struct
259276
| Ok commit -> Lwt.return_some @@ (link, Slack_message.populate_commit repo commit)
260277
)
261278
in
279+
let%lwt bot_user_id =
280+
match ctx.state.bot_user_id with
281+
| Some id -> Lwt.return_some id
282+
| None -> fetch_bot_user_id ()
283+
in
262284
if List.length event.links > 2 then Lwt.return "ignored: more than two links present"
285+
else if Option.value_map bot_user_id ~default:false ~f:(String.equal event.user) then
286+
Lwt.return "ignored: is bot user"
263287
else begin
264288
let links = List.map event.links ~f:(fun l -> l.url) in
265289
let%lwt unfurls = List.map links ~f:process |> Lwt.all |> Lwt.map List.filter_opt |> Lwt.map StringMap.of_list in

lib/api.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ module type Slack = sig
1616
val send_notification : ctx:Context.t -> msg:post_message_req -> (unit, string) Result.t Lwt.t
1717

1818
val send_chat_unfurl : ctx:Context.t -> chat_unfurl_req -> (unit, string) Result.t Lwt.t
19+
20+
val send_auth_test : ctx:Context.t -> unit -> auth_test_res slack_response Lwt.t
1921
end

lib/api_local.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ module Slack_base : Api.Slack = struct
2828
let send_notification ~ctx:_ ~msg:_ = Lwt.return @@ Error "undefined for local setup"
2929

3030
let send_chat_unfurl ~ctx:_ _ = Lwt.return @@ Error "undefined for local setup"
31+
32+
let send_auth_test ~ctx:_ () = Lwt.return @@ Error "undefined for local setup"
3133
end
3234

3335
module Slack : Api.Slack = struct

lib/api_remote.ml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ end
6767
module Slack : Api.Slack = struct
6868
let log = Log.from "slack"
6969

70+
let slack_http_request ?headers ?body meth url read =
71+
match%lwt http_request ?headers ?body meth url with
72+
| Error e -> Lwt.return @@ Error (sprintf "error while querying %s: %s" url e)
73+
| Ok s -> Lwt.return @@ Slack_j.slack_response_of_string read s
74+
7075
let bearer_token_header access_token = sprintf "Authorization: Bearer %s" (Uri.pct_encode access_token)
7176

7277
(** `send_notification ctx msg` notifies `msg.channel` with the payload `msg`;
@@ -123,4 +128,17 @@ module Slack : Api.Slack = struct
123128
)
124129
| Error e -> Lwt.return @@ fmt_error "error while querying %s: %s\nfailed to unfurl Slack links" url e
125130
)
131+
132+
let send_auth_test ~(ctx : Context.t) () =
133+
log#info "retrieving bot information";
134+
let secrets = Context.get_secrets_exn ctx in
135+
match secrets.slack_access_token with
136+
| None -> Lwt.return @@ Error "failed to retrieve Slack access token"
137+
| Some access_token ->
138+
let url = "https://slack.com/api/auth.test" in
139+
let headers = [ bearer_token_header access_token ] in
140+
( match%lwt slack_http_request ~headers `GET url Slack_j.read_auth_test_res with
141+
| Ok res -> Lwt.return @@ Ok res
142+
| Error e -> Lwt.return @@ Error (sprintf "%s\nfailed to retrieve Slack auth info" e)
143+
)
126144
end

lib/atd_adapters.ml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,28 @@ module Branch_filters_adapter = List_or_default_field.Make (struct
4646

4747
let default_value = `List []
4848
end)
49+
50+
module Slack_response_adapter : Atdgen_runtime.Json_adapter.S = struct
51+
let normalize (x : Yojson.Safe.t) =
52+
match x with
53+
| `Assoc fields ->
54+
begin
55+
match List.assoc "ok" fields with
56+
| `Bool true -> `List [ `String "Ok"; x ]
57+
| `Bool false ->
58+
begin
59+
match List.assoc "error" fields with
60+
| `String msg -> `List [ `String "Error"; `String msg ]
61+
| _ -> x
62+
end
63+
| _ | (exception Not_found) -> x
64+
end
65+
| _ -> x
66+
67+
let restore (x : Yojson.Safe.t) =
68+
let mk_fields ok fields = ("ok", `Bool ok) :: List.filter (fun (k, _) -> k <> "ok") fields in
69+
match x with
70+
| `List [ `String "Ok"; `Assoc fields ] -> `Assoc (mk_fields true fields)
71+
| `List [ `String "Error"; `String msg ] -> `Assoc (mk_fields false [ "error", `String msg ])
72+
| _ -> x
73+
end

lib/slack.atd

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,19 @@ type chat_unfurl_res = {
118118
ok: bool;
119119
?error: string option;
120120
}
121+
122+
type auth_test_res = {
123+
url: string;
124+
team: string;
125+
user: string;
126+
team_id: string;
127+
user_id: string;
128+
}
129+
130+
type ('ok, 'err) http_response <ocaml predef module="Base.Result" t="t"> = [
131+
| Ok of 'ok
132+
| Error of 'err
133+
] <ocaml repr="classic">
134+
135+
type 'ok slack_response = ('ok, string) http_response
136+
<json adapter.ocaml="Atd_adapters.Slack_response_adapter">

lib/state.atd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ type pipeline_statuses = branch_statuses map_as_object
1111

1212
(* The serializable runtime state of the bot *)
1313
type state = {
14-
pipeline_statuses <ocaml mutable>: pipeline_statuses
14+
pipeline_statuses <ocaml mutable>: pipeline_statuses;
15+
?bot_user_id <ocaml mutable>: string nullable;
1516
}

lib/state.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ open Base
22
open Common
33
open Devkit
44

5-
let empty : State_t.state = { pipeline_statuses = StringMap.empty }
5+
let empty : State_t.state = { pipeline_statuses = StringMap.empty; bot_user_id = None }
66

77
let refresh_pipeline_status (state : State_t.state) ~pipeline ~(branches : Github_t.branch list) ~status =
88
let update_pipeline_status branch_statuses =

0 commit comments

Comments
 (0)