Skip to content

Commit

Permalink
tbr-bot: update for fly.io deployment
Browse files Browse the repository at this point in the history
Support hosting on fly.io:
- Switch configuration from command line flags to environment
  variables settable in fly.toml or via secrets as appropriate
- add a Makefile and Dockerfile to build a container image
- add an example fly.toml for deployment

Signed-off-by: Denton Gentry <dgentry@tailscale.com>
  • Loading branch information
DentonGentry committed Aug 10, 2022
1 parent 483764b commit 2daad4e
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 1,823 deletions.
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM golang:1.19.0-alpine3.16 as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . ./
RUN go build


FROM alpine:3.16 as tailscale
WORKDIR /app
ENV TSFILE=tailscale_1.28.0_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && tar xzf ${TSFILE} --strip-components=1


# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM alpine:3.16
RUN apk update && apk add ca-certificates iptables ip6tables && rm -rf /var/cache/apk/*

# Copy binary to production image
COPY --from=builder /app/start.sh /start.sh
COPY --from=builder /app/ToBeReviewedBot /ts-tbrbot
COPY --from=tailscale /app/tailscaled /usr/local/bin/tailscaled
COPY --from=tailscale /app/tailscale /usr/local/bin/tailscale
RUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale

# Run on container startup.
CMD ["/start.sh"]
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Build the Docker image and push to fly.io's container registry
# Change $REGISTRY from ts-tbrbot to your fly.io app name and update
# the [build] image in fly.toml to match.

REGISTRY=registry.fly.io/ts-tbrbot:latest

all: build

build:
docker build -t ${REGISTRY} .

push:
docker push ${REGISTRY}
63 changes: 45 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@ The automation in this repository supports a To-Be-Reviewed Pull Request workflo
a followup review within a reasonable amount of time.


### Command line arguments
### Configuration variables
The bot expects to run continuously on a production system, and
supports the following command line arguments:
- `--org="example"`: The GitHub organization to use, like "tailscale".
- `--bugrepo="repo"`: The name of the repository to file followup issues in, like "private".
- `--appname="name"`: The name of the GitHub app account, like "tbr-bot", to use as the
supports the following environment variables:
- `TBRBOT_ORG`: The GitHub organization to use, like "tailscale".
- `TBRBOT_BUGREPO`: The name of the repository to file followup issues in, like "private".
- `TBRBOT_APPNAME`: The name of the GitHub app account, like "tbr-bot", to use as the
author in issues filed.
- `--repos="repo1,repo2"`: A comma-separated list of GitHub repositories to check for
to-be-reviewed PRs, like "oss,private".
- `--appid="123"`: The GitHub App ID, found in https://github.com/organizations/*ORGNAME*/settings/apps/*APPNAME*
- `--appinstall="12345678"`: The GitHub App Install ID for this installation, found in
- `TBRBOT_REPOS`: A comma-separated list of GitHub repositories to check for
to-be-reviewed PRs, like "opensource,private".
- `TBRBOT_APP_ID`: The GitHub App ID, found in https://github.com/organizations/*ORGNAME*/settings/apps/*APPNAME*
- `TBRBOT_APP_INSTALL`: The GitHub App Install ID for this installation, found in
https://github.com/organizations/*ORGNAME*/settings/installations
- `--keyfile="file.pem"`: The name of the file holding a PEM encoded private key,
which can be generated in https://github.com/organizations/*ORGNAME*/settings/apps/*APPNAME*

Additionally, the bot supports the following environment variables which should ideally
be handled by secrets management infrastructure in cloud providers:
- `TBRBOT_APP_PRIVATE_KEY`: a PEM encoded private key, which can be generated in
https://github.com/organizations/*ORGNAME*/settings/apps/*APPNAME*


### Reducing latency using GitHub webhooks
Expand All @@ -37,11 +40,11 @@ followup. Its reaction to a submitted PR can be hastened by setting up a
[GitHub webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks)
for "Pull request reviews" events.

GitHub should be configured to deliver webhook events to `https://Public-DNS-name:10777/webhook`
GitHub should be configured to deliver webhook events to `https://Public-DNS-name/webhook`

- `--webhook_secret_file="filename.txt"`: The shared secret configured in the webhook in
https://github.com/organizations/*ORGNAME*/settings/hooks/*WEBHOOK_ID*?tab=settings
- `--port="1234"` Listen on a port different from the default 10777.
The bot expects to find the shared secret for validating webhook payloads in a `WEBHOOK_SECRET`
environment variable. The shared secret is configured in the webhook in
https://github.com/organizations/*ORGNAME*/settings/hooks/*WEBHOOK_ID*?tab=settings


### Monitoring
Expand All @@ -50,15 +53,39 @@ to monitor whether the bot is working. Finding out on the eve of an audit that t
bot has been offline for an extended period would be ruinous.

In addition to `/webhook` the bot also exports metrics:
- `https://MagicDNS-name:10777/debug/vars` in JSON format
- `https://MagicDNS-name:10777/debug/varz` in Prometheus metric format
- `https://Tailscale-MagicDNS-name/debug/vars` in JSON format
- `https://Tailscale-MagicDNS-name/debug/varz` in Prometheus metric format

The `/debug` endpoints can only be reached from a local [Tailscale](https://tailscale.com)
tailnet. It is reasonable to allow public Internet access to https://servername:10777/
tailnet. It is reasonable to allow public Internet access to https://Public-DNS-name/
for GitHub to be able to deliver webhooks, TBR-bot will restrict the other endpoints to
only be accessible via a private tailnet connection.

A metric of interest for monitoring is `tbrbot_repos_checked`, which counts the number of times
the bot has checked a repository for submitted PRs. This is expected to increment at least once
per hour. An alert when `tbrbot_repos_checked` goes N hours with no change is a reasonable way
to monitor TBR-bot's operation.


### Hosting
The included Dockerfile and example fly.toml are suitable to run the tbr-bot
[hosted on fly.io](https://fly.io/).

We recommend forking this repository and making local modifications to the supplied fly.toml
to set it to the name of your instance and update the environment variables to correspond
to the GitHub repositories you want it to watch.

The bot needs a small amount of persistent storage for its Tailscale state, plus the various
configuration and secrets described above.
```
$ flyctl volumes create tbrbot_data --region sjc --size 1
$ flyctl scale count 1
$ flyctl secrets set TS_AUTHKEY=... TBRBOT_APP_ID=... TBRBOT_APP_INSTALL=...
$ flyctl secrets set TBRBOT_WEBHOOK_SECRET=...
$ flyctl secrets set TBRBOT_APP_PRIVATE_KEY=- < pem
$ flyctl ips allocate-v6
```

We recommend using a [one-time authkey with Tags set](https://tailscale.com/blog/acl-tags-ga/) to
authorize the bot to join the tailnet. Once the bot has run once and written its state
to persistent storage, the `TS_AUTHKEY` secret should be removed.
55 changes: 55 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Manually:
# $ flyctl volumes create tbrbot_data --region sjc --size 1
# $ flyctl scale count 1
# $ flyctl secrets set TS_AUTHKEY=... TBRBOT_APP_ID=... TBRBOT_APP_INSTALL=...
# $ flyctl secrets set TBRBOT_WEBHOOK_SECRET=...
# $ flyctl secrets set TBRBOT_APP_PRIVATE_KEY=- < pem
# $ flyctl ips allocate-v6

app = "example-tbrbot"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[build]
image = "registry.fly.io/ts-tbrbot:latest"

[env]
TBRBOT_APPNAME = "tbr-bot"
TBRBOT_BUGREPO = "private"
TBRBOT_ORG = "my-organization"
TBRBOT_REPOS = "private,opensource"

[experimental]
allowed_public_ports = []
auto_rollback = true

[mounts]
destination = "/root"
source = "tbrbot_data"

[[services]]
http_checks = []
internal_port = 8080
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = "connections"

[[services.ports]]
force_https = true
handlers = ["http"]
port = 80

[[services.ports]]
handlers = ["tls", "http"]
port = 443

[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/tailscale/tbr-audit
module github.com/tailscale/ToBeReviewedBot

go 1.19

Expand Down
Loading

0 comments on commit 2daad4e

Please sign in to comment.