Skip to content

Latest commit

 

History

History

examples

Examples and Documentation


Installation and Deployments

Bashbot can be deployed in a number of different ways, to leverage the host's environment-variables and network. The source of bashbot has a makefile to aid in automated testing, that can also be used to run bashbot locally. Clone the source, and run make help for an updated list of options, or use this read-me to run commands manually.

Note: Prior to version 2, Bashbot required a "classic app" to be configured to get the correct type of token to connect to Slack. After logging into Slack via browser, visit https://api.slack.com/apps?new_classic_app=1 to set up a new "legacy bot user", "Bot User OAuth Access Token," add bashbot to your workspace, and invite to a channel. See the (archived) Setup/Deployment Examples Repository for more detailed information about how to deploy Bashbot (v1) in your infrastructure.


Binary

Bashbot is written in golang, and has release automation to cross compile go-binaries for linux/darwin and amd64/arm64. They can be downloaded from the releases page and run from the command line with the slack-app-token and slack-bot-token saved as environment variables.

# Download the default configuration files
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/.tool-versions -q -O ${PWD}/.tool-versions
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-config.yaml -q -O ${PWD}/config.yaml
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-env-file -q -O ${PWD}/.env

# Set a path to your local configuration file
export BASHBOT_CONFIG_FILEPATH=${PWD}/config.yaml
# Set `Bot User OAuth Access Token` as SLACK_BOT_TOKEN environment variable
export SLACK_BOT_TOKEN=xoxb-xxxxxxxxx-xxxxxxx
# Set `Bot App Access Token` as SLACK_APP_TOKEN environment variable
export SLACK_APP_TOKEN=xapp-xxxxxxxxx-xxxxxxx
# Set log-level (default: info)
export LOG_LEVEL=info
# Set log-format (default: text) [text|json]
export LOG_FORMAT=text
# os: linux, darwin
export os=$(uname | tr '[:upper:]' '[:lower:]')
# arch: amd64, arm64
export arch=amd64
test "$(uname -m)" == "aarch64" && export arch=arm64

# Latest bashbot version/tag
export latest_bashbot_version=$(curl -s https://api.github.com/repos/mathew-fleisch/bashbot/releases/latest | grep tag_name | cut -d '"' -f 4)

# Remove any existing bashbot binaries
rm -rf /usr/local/bin/bashbot || true

# Get correct binary for host machine and place in user's path
wget -qO /usr/local/bin/bashbot https://github.com/mathew-fleisch/bashbot/releases/download/${latest_bashbot_version}/bashbot-${os}-${arch}

# Make bashbot binary executable
chmod +x /usr/local/bin/bashbot

# Disable security check on macs (only run once)
test "${os}" == "darwin" && xattr -d com.apple.quarantine /usr/local/bin/bashbot

# To verify installation run version or help commands
bashbot version
# bashbot-darwin-amd64    v2.0.5

bashbot --help
#  ____            _     ____        _   
# |  _ \          | |   |  _ \      | |  
# | |_) | __ _ ___| |__ | |_) | ___ | |_ 
# |  _ < / _' / __| '_ \|  _ < / _ \| __|
# | |_) | (_| \__ \ | | | |_) | (_) | |_ 
# |____/ \__,_|___/_| |_|____/ \___/ \__|
# Bashbot is a slack bot, written in golang, that can be configured
# to run bash commands or scripts based on a configuration file.

# Usage:
#   bashbot [command]

# Available Commands:
#   completion           Generate the autocompletion script for the specified shell
#   help                 Help about any command
#   install-dependencies Cycle through dependencies array in config file to install extra dependencies
#   run                  Run bashbot
#   send-message         Send stand-alone slack message
#   version              Get current version

# Flags:
#       --config-file string       [REQUIRED] Filepath to config.yaml file (or environment variable BASHBOT_CONFIG_FILEPATH set)
#   -h, --help                     help for bashbot
#       --log-format string        Display logs as json or text (default "text")
#       --log-level string         Log elevel to display (info,debug,warn,error) (default "info")
#       --slack-app-token string   [REQUIRED] Slack app token used to authenticate with api (or environment variable SLACK_APP_TOKEN set)
#       --slack-bot-token string   [REQUIRED] Slack bot token used to authenticate with api (or environment variable SLACK_BOT_TOKEN set)
#   -t, --toggle                   Help message for toggle

# Use "bashbot [command] --help" for more information about a command.

# Run install-vendor-dependencies path
bashbot install-dependencies \
  --log-level "$LOG_LEVEL" \
  --log-format "$LOG_FORMAT"

# Run Bashbot binary passing the config file and the Slack token
bashbot run \
  --log-level "$LOG_LEVEL" \
  --log-format "$LOG_FORMAT"

Binary asdf

Bashbot can be installed via the asdf version manager with the asdf plugin for bashbot. It can also be used in github actions as a simple text message stage, or as a gating mechanism to manually approve/reject a github action, or as a debugging breakpoint for troubleshooting a github action. These techniques should be applicable in any CI system.

# Download the default configuration files
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/.tool-versions -q -O ${PWD}/.tool-versions
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-config.yaml -q -O ${PWD}/config.yaml
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-env-file -q -O ${PWD}/.env

# Set a path to your local configuration file
export BASHBOT_CONFIG_FILEPATH=${PWD}/config.yaml
# Set a path to your local configuration file
export BASHBOT_CONFIG_FILEPATH=${PWD}/bashbot/config.yaml
# Set `Bot User OAuth Access Token` as SLACK_BOT_TOKEN environment variable
export SLACK_BOT_TOKEN=xoxb-xxxxxxxxx-xxxxxxx
# Set `Bot App Access Token` as SLACK_APP_TOKEN environment variable
export SLACK_APP_TOKEN=xapp-xxxxxxxxx-xxxxxxx
# Set log-level (default: info)
export LOG_LEVEL=info
# Set log-format (default: text) [text|json]
export LOG_FORMAT=text

asdf plugin add bashbot
asdf install bashbot 2.0.5
asdf global bashbot 2.0.5

# To verify installation run version or help commands
bashbot version
# bashbot-darwin-amd64    v2.0.5

# See binary instructions after `bashbot verison`

docker

# Set `Bot User OAuth Access Token` as SLACK_BOT_TOKEN environment variable
export SLACK_BOT_TOKEN=xoxb-xxxxxxxxx-xxxxxxx
# Set `Bot App Access Token` as SLACK_APP_TOKEN environment variable
export SLACK_APP_TOKEN=xapp-xxxxxxxxx-xxxxxxx

# Get the sample config.yaml
wget -O config.yaml https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-config.yaml

# Pass environment variable and mount configuration yaml to run container
docker run -it --rm \
  --pull always \
  --name bashbot \
  -v ${PWD}/config.yaml:/bashbot/config.yaml \
  -e BASHBOT_CONFIG_FILEPATH="/bashbot/config.yaml" \
  -e SLACK_BOT_TOKEN \
  -e SLACK_APP_TOKEN \
  -e LOG_LEVEL="info" \
  -e LOG_FORMAT="text" \
  mathewfleisch/bashbot:latest

kubernetes

To deploy bashbot with raw kubernetes manifests, see the rendered helm template for an example deployment with service account: kubernetes-manifests-withsa.yaml

Note: For bashbot to pick up changes to the configmap/values, a running pod must be deleted to trigger a restart.

# generated with
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/.tool-versions -q -O .tool-versions
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-config.yaml -q -O config.yaml

export NAMESPACE=bashbot
export BOTNAME=bashbot

helm template --debug \
  --version=${TARGET_VERSION} \
  --namespace ${NAMESPACE} \
  --set namespace=${NAMESPACE} \
  --set botname=${BOTNAME} \
  --set-file '\.tool-versions'=${PWD}/.tool-versions \
  --set-file 'config\.yaml'=${PWD}/config.yaml \
  --repo https://mathew-fleisch.github.io/bashbot \
  ${BOTNAME} bashbot > kubernetes-manifests-withsa.yaml

To deploy bashbot with raw kubernetes manifests, see the rendered helm template for an example deployment WITHOUT a service account: kubernetes-manifests.yaml

Note: For bashbot to pick up changes to the configmap/values, a running pod must be deleted to trigger a restart.

# generated with
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/.tool-versions -q -O .tool-versions
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-config.yaml -q -O config.yaml

export NAMESPACE=bashbot
export BOTNAME=bashbot

helm template --debug \
  --version=${TARGET_VERSION} \
  --namespace ${NAMESPACE} \
  --set namespace=${NAMESPACE} \
  --set botname=${BOTNAME} \
  --set serviceAccount.create=false \
  --set-file '\.tool-versions'=${PWD}/.tool-versions \
  --set-file 'config\.yaml'=${PWD}/config.yaml \
  --repo https://mathew-fleisch.github.io/bashbot \
  ${BOTNAME} bashbot > kubernetes/kubernetes-manifests.yaml

helm

To install bashbot from the public helm repo, the slack app/bot tokens are required to be saved as kubernetes secret, and local versions of the config.yaml and .tool-versions file. To install the local helm chart from source, run the makefile target make helm-install after exporting the slack-app-token and slack-bot-token environment variables.

Note: For bashbot to pick up changes to the configmap/values, a running pod must be deleted to trigger a restart.

# Define your bashbot instance and namespace names
export BOTNAME=bashbot
export NAMESPACE=bashbot
export TARGET_VERSION=v2.0.5

# Get sample-env-file, sample-config.yaml, and .tool-versions
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/.tool-versions -q -O ${PWD}/.tool-versions
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-config.yaml -q -O ${PWD}/config.yaml
wget https://raw.githubusercontent.com/mathew-fleisch/bashbot/main/sample-env-file -q -O ${PWD}/sample-env-file

# Add the public helm repo (one time)
helm repo add bashbot https://mathew-fleisch.github.io/bashbot

# Build kubernetes secrets from .env file (don't forget to fill the .env file with your secrets)
cat ${PWD}/sample-env-file | envsubst > ${PWD}/.env
kubectl --namespace ${NAMESPACE} create secret generic ${BOTNAME}-env \
  $(cat ${PWD}/.env | grep -vE '^#' | sed -e 's/export\ /--from-literal=/g' | tr '\n' ' ')

# Install a specific version of bashbot (remove --version for latest)
helm install --debug --wait \
  --version=${TARGET_VERSION} \
  --namespace ${NAMESPACE} \
  --set namespace=${NAMESPACE} \
  --set botname=${BOTNAME} \
  --set-file '\.tool-versions'=${PWD}/.tool-versions \
  --set-file 'config\.yaml'=${PWD}/config.yaml \
  --repo https://mathew-fleisch.github.io/bashbot \
  ${BOTNAME} bashbot

KinD

For local development on bashbot, a kind cluster is used for testing.

KinD Prerequisites

Note: you can use the asdf version manager to install dependencies used in the makefile with the following .tool-versions

action-validator 0.1.2
dockle 0.4.3
golangci-lint 1.44.2
helm 3.10.3
kubectl 1.26.0
kubectx 0.9.4
kustomize 4.5.7

To set up a local KinD cluster run the following commands:

# Copy .env, config.yaml and .tool-versions sample files to helm directory and replace with custom values.
cp sample-env-file .env
cp sample-config.yaml config.yaml
make test-kind

# At this point you should have a KinD cluster running with a bashbot deployment inside
kubectl cluster-info
helm --namespace bashbot list
# Use these basic kubectl commands (one at a time) to verify (use `-o yaml` for more detailed information)
kubectl --namespace bashbot get deployments
kubectl --namespace bashbot get pods
kubectl --namespace bashbot get configmaps
kubectl --namespace bashbot get serviceaccounts
kubectl --namespace bashbot get clusterrolebinding
kubectl --namespace bashbot get secrets

ArgoCD

Bashbot works great with ArgoCD because the values.yaml of the helm chart can override/set/customize any value, to customize for any deployment scenario. Note: updating the values in the config.yaml or .tool-versions section, only update a config-map, and the bashbot pod will need to be deleted, so the replacement pod will include the new configmap. example-argocd-application.yam

Note: For bashbot to pick up changes to the configmap/values, a running pod must be deleted to trigger a restart.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: bashbot
  namespace: argocd
spec:
  project: default
  source:
    chart: bashbot
    repoURL: https://mathew-fleisch.github.io/bashbot
    targetRevision: v2.0.5
    helm:
      releaseName: bashbot
      values: |
        botname: bashbot
        namespace: bots
        log_level: info
        log_format: text
        image:
          repository: mathewfleisch/bashbot
          pullPolicy: IfNotPresent
          command:
          - /bashbot/entrypoint.sh
        serviceAccount:
          create: true
        .tool-versions: |
          [contents of .tool-versions]
        config.yaml: |
          [contents of config.yaml]
  destination:
    server: "https://kubernetes.default.svc"
    namespace: bots
  syncPolicy:
    syncOptions:
        - CreateNamespace=true
    automated:
      prune: true
      selfHeal: true

config.yaml

sample-config.yaml The config.yaml file is defined as an array of yaml objects keyed by 'tools' and 'dependencies.' The dependencies section defines any resources that need to be downloaded or cloned from a repository before execution of commands. Each command is configured by a single object. For instance, the most simple command (hello world) returns a simple message when triggered, in the ping example.

name: Ping/Pong
description: Return pong on pings
envvars: []
dependencies: []
help: "!bashbot ping"
trigger: ping
location: /bashbot/
command:
  - echo "pong"
parameters: []
log: true
ephemeral: false
response: text
permissions:
  - all

Parameters and Arguments

Commands can take arguments, but require the values to either match a hard-coded list of values, value, from a sub-command, or a regular expression to be valid. Before each command is executed, a few environment variables are set, and can be leveraged in commands TRIGGERED_USER_NAME TRIGGERED_USER_ID TRIGGERED_CHANNEL_NAME TRIGGERED_CHANNEL_ID

  • name(string): title of command
  • description(string): information about command
  • envvars(array of strings): required environment variables to run command
  • dependencies(array of strings): required pre-installed tools to run command
  • help(string): message to users about how to execute
  • trigger(string): single word to execute command
  • location(string): absolute/relative path to set context
  • command(array of strings): command to pass to bash -c
  • parameters(array of objects):
    • name(string): title of command argument
    • allowed(array of strings): hard-coded list of allowed values
    • description(string): information about command argument
    • match(string): regular expression to match allowed values
    • source(array of strings): bash command to build list of allowed values
  • log(boolean): whether to log command to log channel
  • ephemeral(boolean): send response to user as ephemeral message
  • response(text|code|file): send response in raw text, surrounded by markdown code tics, or as a text file
  • permissions(array of strings): list of channel ids to restrict command to (all for unrestricted access)

An example of a command that uses a hard-coded parameter to either run the date command or the uptime command on the host.

name: Date or Uptime
description: Show the current time or uptime
envvars: []
dependencies: []
help: "!bashbot time"
trigger: time
location: /bashbot/
command:
  - "echo \"Date/time: $(${command})\""
parameters:
  - name: command
    allowed:
      - date
      - uptime
log: true
ephemeral: false
response: code
permissions:
  - all

An example of a command that uses source to build a list of allowed values is the describe example. Bashbot will first use the command line yaml parser yq to build a list of trigger values yq e '.tools[] | .trigger' ${BASHBOT_CONFIG_FILEPATH}. A user would then only be able to "describe" each command that has a "trigger" value (i.e. !bashbot describe describe would show the following yaml)

name: Describe Bashbot [command]
description: Show the yaml object for a specific command
envvars:
  - BASHBOT_CONFIG_FILEPATH
dependencies:
  - yq
help: "!bashbot describe [command]"
trigger: describe
location: /bashbot/
command:
  - yq e '.tools[] | select(.trigger=="${command}")' ${BASHBOT_CONFIG_FILEPATH}
parameters:
  - name: command
    allowed: []
    description: a command to describe ('bashbot list')
    source:
      - yq e '.tools[] | .trigger' ${BASHBOT_CONFIG_FILEPATH}
log: true
ephemeral: false
response: code
permissions:
  - all

An example of a command that has regular expression match parameter, is the aqi example. This command takes one argument, a zip code and a regular expression is used to validate it. The aqi script is used to curl the Air Now API, and form a custom response with emojis.

name: Air Quality Index
description: Get air quality index by zip code
envvars:
  - AIRQUALITY_API_KEY
dependencies:
  - curl
  - jq
help: "!bashbot aqi [zip-code]"
trigger: aqi
location: /bashbot/vendor/bashbot/examples/aqi
command:
  - "./aqi.sh ${zip}"
parameters:
  - name: zip
    allowed: []
    description: any zip code
    match: (^\d{5}$)|(^\d{9}$)|(^\d{5}-\d{4}$)
log: true
ephemeral: false
response: text
permissions:
  - all