Skip to content

Commit

Permalink
Merge pull request #65 from keybase/david/bot-announce
Browse files Browse the repository at this point in the history
Add feature for bot to announce itself at startup
  • Loading branch information
ddworken authored Sep 11, 2019
2 parents 38f5a25 + 6bbc7eb commit 44f7145
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 1 deletion.
20 changes: 20 additions & 0 deletions docs/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ export CHAT_CHANNEL="team.prod#ssh-provision"
export CHAT_CHANNEL="team.ssh_bot#general"
```

### Announcement

The `ANNOUNCEMENT` environment variable contains a string that will be announced in all of the configured teams when
the bot is started. This is useful if you would like the bot to announce the fact it has started and granted access in
a given team. The `ANNOUNCEMENT` environment variable supports a number of templating variables that will be instantiated
based off of the current config. These are:

* `{USERNAME}` will be replaced with the username of the bot
* `{CURRENT_TEAM}` will be replaced with the team that the message is being sent in
* `{TEAMS}` will be replaced with the comma separated list of teams that the bot is running in

Examples:

```bash
export ANNOUNCEMENT="SSH CA bot starting up..."
export ANNOUNCEMENT="Hello! I'm {USERNAME} and I'm an SSH bot! See github.com/keybase/bot-sshca for information on using Keybase for SSH."
export ANNOUNCEMENT="Hello! I'm {USERNAME} and I'm an SSH bot! I'm currently listening in {TEAMS}."
export ANNOUNCEMENT="Hello! I'm {USERNAME} and I'm an SSH bot! Being in {CURRENT_TEAM} will grant you SSH access to certain servers. Reach out to @dworken for more information."
```

## Developer Options

These environment variables are mainly useful for dev work. For security reasons, it is recommended always to run a
Expand Down
48 changes: 47 additions & 1 deletion src/keybaseca/bot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,18 @@ func GetUsername(conf config.Config) (string, error) {
return username, nil
}

// Start the keybaseca bot in an infinite loop. Does not return unless it encounters an error.
// Start the keybaseca bot in an infinite loop. Does not return unless it encounters an unrecoverable error.
func StartBot(conf config.Config) error {
kbc, err := GetKBChat(conf)
if err != nil {
return fmt.Errorf("error starting Keybase chat: %v", err)
}

err = sendAnnouncementMessage(conf, kbc)
if err != nil {
return fmt.Errorf("failed to start bot due to error while sending announcement: %v", err)
}

sub, err := kbc.ListenForNewTextMessages()
if err != nil {
return fmt.Errorf("error subscribing to messages: %v", err)
Expand Down Expand Up @@ -144,3 +149,44 @@ func isConfiguredTeam(conf config.Config, teamName string, channelName string) b
}
return false
}

type AnnouncementTemplateValues struct {
Username string
CurrentTeam string
Teams []string
}

func buildAnnouncement(template string, values AnnouncementTemplateValues) string {
replacements := map[string]string{
"{USERNAME}": values.Username,
"{CURRENT_TEAM}": values.CurrentTeam,
"{TEAMS}": strings.Join(values.Teams, ", "),
}

templatedMessage := template
for templateStr, templateVal := range replacements {
templatedMessage = strings.Replace(templatedMessage, templateStr, templateVal, -1)
}

return templatedMessage
}

func sendAnnouncementMessage(conf config.Config, kbc *kbchat.API) error {
if conf.GetAnnouncement() == "" {
// No announcement to send
return nil
}
for _, team := range conf.GetTeams() {
announcement := buildAnnouncement(conf.GetAnnouncement(),
AnnouncementTemplateValues{Username: kbc.GetUsername(),
CurrentTeam: team,
Teams: conf.GetTeams()})

var channel *string
_, err := kbc.SendMessageByTeamName(team, announcement, channel)
if err != nil {
return err
}
}
return nil
}
24 changes: 24 additions & 0 deletions src/keybaseca/bot/bot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package bot

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestBuildAnnouncement(t *testing.T) {
values := AnnouncementTemplateValues{Username: "my_username", CurrentTeam: "my_cur_team", Teams: []string{"my_team1", "my_team2"}}

require.Equal(t, "",
buildAnnouncement("", values))
require.Equal(t, "no templates",
buildAnnouncement("no templates", values))
require.Equal(t, "repeated my_username my_username my_username",
buildAnnouncement("repeated {USERNAME} {USERNAME} {USERNAME}", values))
require.Equal(t, "all my_username my_cur_team my_team1, my_team2",
buildAnnouncement("all {USERNAME} {CURRENT_TEAM} {TEAMS}", values))
require.Equal(t, "bogus {FOO}",
buildAnnouncement("bogus {FOO}", values))
require.Equal(t, "double-is-not-escape {my_username}",
buildAnnouncement("double-is-not-escape {{USERNAME}}", values))
}
6 changes: 6 additions & 0 deletions src/keybaseca/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Config interface {
GetChannelName() string
GetLogLocation() string
GetStrictLogging() bool
GetAnnouncement() string
DebugString() string
}

Expand Down Expand Up @@ -250,6 +251,11 @@ func (ef *EnvConfig) GetChannelName() string {
return channel
}

// Get the announcement string used when the bot is started up. May be empty.
func (ef *EnvConfig) GetAnnouncement() string {
return os.Getenv("ANNOUNCEMENT")
}

// Dump this EnvConfig to a string for debugging purposes
func (ef *EnvConfig) DebugString() string {
return fmt.Sprintf("CAKeyLocation='%s'; KeybaseHomeDir='%s'; KeybasePaperKey='%s'; KeybaseUsername='%s'; "+
Expand Down
1 change: 1 addition & 0 deletions tests/envFiles/test_env_1
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export KEYBASE_PAPERKEY="$BOT_PAPERKEY"
export KEYBASE_USERNAME="$BOT_USERNAME"
export CHAT_CHANNEL="$SUBTEAM.ssh#ssh-provision"
export CA_KEY_LOCATION="/shared/keybase-ca-key"
export ANNOUNCEMENT='Hello my name is {USERNAME}. This is {CURRENT_TEAM} and the configured teams are {TEAMS}'

0 comments on commit 44f7145

Please sign in to comment.