Has this blog been helpful? Please consider supporting this blog (and my open-source libraries). Thanks!
For a limited time, GitHub will match your support.

Slash Commands

I’m not very familiar with the term “ChatOps”, but I’ve seen ChatOps actually used a lot. The idea is that you can set up chat bots to listen to your team’s chat and take actions based on commands you can type in the chat.

What we’ll be setting up here is pretty close to that; we want to be able to add a comment to a PR with a “slash command” that will do our deploy (or teardown) for us. Specifically, we’ll be using:

  • /deploy to deploy a PR to its staging environment.
  • /teardown to tear down a PR staging environment when we’re done with the PR.

Dispatching Slash Commands

The way we’ll be setting this up is to have one GitHub Action that listens for PR comments and decides if they have any slash commands. For any slash commands, we want to dispatch an event to our repository.

In your GitHub repository, open up the Actions tab and choose “Set up a workflow yourself”. Name the file slash-commands.yml and paste this in:

# Translates slash-commands in issue comments to repository-dispatch events.

# Name of the action (displayed in the Actions tab)
name: Slash command dispatch

# Triggers for this action.
#  This one only runs when a comment is added to an issue.
#  (on GitHub, pull requests are one kind of "issue")
on:
  issue_comment:
    types: [ created ]

# When the trigger fires, we run these jobs.
jobs:
  dispatch: #  We just have one job, called "dispatch"
    runs-on: ubuntu-latest # The OS we run on. Doesn't really matter for this simple action.
    steps: # This job only has one step, called "Dispatch slash command"
      - name: Dispatch slash command
        uses: peter-evans/[email protected] # Uses a pre-built action from the Marketplace
        with: # These are the parameters passed to the action
          token: ${{ secrets.DISPATCH_TOKEN }} # This action needs a personal access token in order to dispatch
          reactions: false # By default, this action will add reactions to the slash command comment; this turns those off
          issue-type: pull-request # We only want to look for slash commands in pull requests, not other issues
          commands: deploy, teardown # The slash commands we look for: /deploy and /teardown

In this case, our GitHub Action is simple; slash-command-dispatch is specifically designed for matching slash commands in issue and/or PR comments, and dispatching a command to the repository.

Note that we’re passing a token to this GitHub Action, and we’re taking the value from secrets.DISPATCH_TOKEN. We don’t have that secret yet, so let’s set that up now. In order to dispatch, slash-command-dispatch needs a token with write access to the repository. You can get one by following the GitHub directions; when creating your token, you’ll want public_repo scope if your repository is public - otherwise, you’ll want repo scope. Copy that access token value once it’s created.

Next, create a repository secret named DISPATCH_TOKEN and paste that value in… and if you did that without doing any verification, then you just failed Security 101.

On a more serious note, right now the world of GitHub Actions (and its Marketplace) are in the “just trying to get it to work” stage. And in that stage of technology adoption, security is often overlooked. So when you’re reading some blog on the Internet and it tells you to make a personal access token and paste it somewhere, you should take a step back and really think about what’s going on.

Security Concerns

At the very least, take a look at the code that’s receiving the token. I’m using peter-evans/slash-command-dispatch in the example above. Does it look like an upstanding project? Good documentation? High(ish) number of stars? Not forked from a different project? Who is this “Peter Evans” and does he seem like a trustworthy person? Go ahead and open the action’s repository; does the code look OK?

Any time you’re passing a token to an action, you should do this kind of research, if not more. If you’re not comfortable with pasting a personal access token, there are a few alternative approaches.

Alternative Approaches

The security concerns above are due to the choice to dispatch the repository events rather than handling them directly, so we end up handing a token to a third-party GitHub Action.

Alternative approaches include:

  • Performing a security audit of the GitHub Action and then SHA-locking to that specific version. I.e., instead of peter-evans/[email protected], use peter-evans/[email protected].
  • Performing a security audit of the GitHub Action, cloning it to your own personal GitHub Action, and using that one instead.
  • Writing your own GitHub Action that does essentially the same thing.
  • Creating a separate GitHub account, inviting that account to your repository (in a write role), accepting that invitation, and using a public_repo/repo token from that account instead of your personal account.
    • This ensures that the token can only be used to disrupt this one repository, instead of all your repositories.
    • It does still allow write access to this repository, though.
  • Handling all slash commands directly instead of dispatching.
    • You have to either combine all slash command handling into a single file (which makes your workflow file messy), or have multiple slash command handler actions (which makes your PR “checks” section messy).
    • At the time of this writing, there isn’t a great GitHub Action for parsing multiple slash commands and setting step outputs that can be used by future steps.
    • Even if such an action did exist, the resulting slash-command.yml file would get rather long and ugly with if: conditionals throughout.
    • However, this is the only alternative that is fully safe, since you would no longer require a personal access token at all. Because it doesn’t do dispatching.

I’ve tried out a few alternatives, and I tend to prefer either just doing it the easy way (as done in this post), or creating a separate GitHub account (to limit the scope of a breached token to this single repository). I don’t like handling all slash commands directly instead of dispatching, for reasons that will become more clear when we extend this solution to automate deploy and teardown commands (in a future post).

Back to The Goal

The rest of this blog series assumes that you have done a sufficient security check and have stored a token in the repository secrets, named DISPATCH_TOKEN.

Dispatch

The slash-command-dispatch action recognizes slash commands and then sends a repository dispatch event to the repository. repository_dispatch is a special event that you can listen for (with another GitHub Action) and respond to.

slash-command-dispatch follows a convention where the commands it listens to (deploy and teardown in our case) are sent with the repository_dispatch event, with a -command suffix. So, just like today’s GitHub Action listened for an issue_comment event of type created, next time we’ll write GitHub Actions that listen for a repository_dispatch event of type deploy-command or teardown-command.

Next Steps

At this point, you should have a “ChatOps bot” of sorts that listens for /deploy and /teardown comments on your pull requests, and then translates those into repository_dispatch events. Next time we’ll add handlers for those events.