Skip to main content

octotail

PyPI License: Unlicense Actions Status Code coverage Code style: black

Live tail GitHub Action runs on git push. It's cursed.

Motivation

I really liked how Codecrafters test runs are mirrored back right in the terminal when you git push, so I thought: "surely this is something the gh CLI supports". It doesn't.

A couple of hours of messing with HTTPS mitm proxies, websockets, headless browsers, you-name-it, and octotail was born.

Wait, what?!

Invoked with a commit_sha (and optionally --workflow and/or --ref-name), it polls the GitHub API for a matching, active run. When a job associated with the run starts, it instructs a headless chromium-based browser to visit the job's page.

The browser's traffic passes through a mitmproxy instance that it uses to extract the authenticated WebSocket subscriptions for live tailing.

The WebSocket address and subscribe messages are then passed to the tailing workers.

The headless browser tabs are cleaned up immediately after the WebSocket extraction, so the overhead is minimal. (well, it's still an empty browser)

Prerequisites

  • python 3.12
  • a working chromium-based browser under /usr/bin/chromium

Installation

Via uvx

One can simply and hassle-free invoke octotail through uvx.

First, generate the proxy root certificate:

uvx --from=octotail octotailx generate-cert

Then, see Install the generated proxy root certificate for instructions on how to install the generated certificate on your platform.

Finally, simply invoke it via:

uvx --from=octotail octotail

Or alias it as octotail:

# change .zshrc to .bashrc, config.fish, etc. if needed
echo "alias octotail='uvx --from octotail octotail'" >> ~/.zshrc

Pypi package

mkdir octotail && cd octotail
python3 -mvenv .venv && source .venv/bin/activate
pip3 install octotail

# change .zshrc to .bashrc, config.fish, etc.
echo "alias octotail='$(pwd)/.venv/bin/python3 $(pwd)/.venv/bin/octotail'" >> ~/.zshrc
echo "alias octotailx='$(pwd)/.venv/bin/python3 $(pwd)/.venv/bin/octotailx'" >> ~/.zshrc

Via git and make

git clone https://github.com/getbettr/octotail.git
cd octotail
make
sudo make install

Post-install

Install the generated proxy root certificate

This step is highly platform-dependent.

On Arch Linux
sudo trust anchor ~/.local/share/octotail/mitmproxy/mitmproxy-ca-cert.cer

On macOS

sudo security add-trusted-cert -d -p ssl -p basic \
  -k /Library/Keychains/System.keychain \
  ~/local/.share/octotail/mitmproxy/mitmproxy-ca-cert.pem

Others

Please refer to the "Installing the mitmproxy CA certificate manually" section of the mitmproxy documentation, changing ~/.mitmproxy with ~/.local/share/octotail/mitmproxy where appropriate.

Usage

# octotail --help

 Usage: octotail [OPTIONS] COMMIT_SHA

 Find an active workflow run for the given COMMIT_SHA (and optionally --workflow and/or --ref-name)
 and attempt to tail its logs.
 NOTE: the COMMIT_SHA has to be of the full 40 characters length.

-- Arguments ---------------------------------------------------------------------------------------
  *    commit_sha      TEXT  Full commit SHA that triggered the workflow.
                             [required]

-- Authentication ----------------------------------------------------------------------------------
  *  --gh-pat             TEXT  GitHub personal access token. (for API auth)
                                [env var: OCTOTAIL_GH_PAT]
                                [required]
  *  --gh-user            TEXT  GitHub username. (for web auth)
                                [env var: OCTOTAIL_GH_USER]
                                [required]
  *  --gh-pass            TEXT  GitHub password. (for web auth)
                                [env var: OCTOTAIL_GH_PASS]
                                [required]
     --gh-otp             TEXT  GitHub OTP. (for web auth, if 2FA is on)
                                [env var: OCTOTAIL_GH_OTP]
                                [default: None]
     --gh-otps-cmd        TEXT  Command for generating GitHub OTPs. Should generate at least 2
                                codes, one per line. (for web auth, if 2FA is on)
                                [env var: OCTOTAIL_GH_OTPS_CMD]
                                [default: None]

-- Workflow filters --------------------------------------------------------------------------------
  --workflow  -w      TEXT       Only consider workflows with this name.
  --ref-name  -r      TEXT       Only consider workflows triggered by this ref. Example:
                                 refs/heads/main
  --repo      -R      USER/REPO  Use this GitHub repo to look for workflow runs. If unspecified,
                                 will look for a remote matching 'git@github.com:user/repo.git' in
                                 the current directory. Examples: user/repo OR org_name/repo

-- Others ------------------------------------------------------------------------------------------
  --headless    --no-headless             Run browser in headless mode.
                                          [env var: OCTOTAIL_HEADLESS]
                                          [default: headless]
  --port                         INTEGER  Port the proxy will listen on.
                                          [env var: OCTOTAIL_PROXY_PORT]
                                          [default: (random in range 8100-8500)]
  --version                               Show the version and exit.
  --help                                  Show this message and exit.

Tail after push

A simple use case is tailing a workflow run right after git push:

If simply pushing the HEAD of the current branch:

git push
octotail $(git rev-parse HEAD)

Or if pushing to a different remote branch:

git push origin main
octotail $(git rev-parse origin/main) -r refs/heads/main

Or if pushing a tag:

git push origin v1.0.42
octotail $(git rev-parse v1.0.42^{commit}) -r refs/tags/v1.0.42

NEW: octotailx install-proxy-remote

As a post-receive hook

A slightly more advanced use case that allows streaming the run outputs on git push without invoking octotail explicitly, similar to Codecrafters test runs.

For this to work we'll need control over the remote's output, so we can't use the GitHub remote directly. Instead, we'll use a bare repository as our proxy remote and set up its post-receive hook to call octotail.

cd your-original-repo
export PROXY_REPO="/wherever/you/want/to/store/the/proxy-repo"

mkdir -p $PROXY_REPO
git clone --mirror "$(git remote get-url origin)" $PROXY_REPO
git remote add proxy $PROXY_REPO
# back to octotail
cd -

cp examples/post-receive.sample $PROXY_REPO/hooks/post-receive

Edit $PROXY_REPO/hooks/post-receive and change things according to your setup:

  • set _GH_USER to your GitHub username
  • set _GH_PASS_CMD to a command that outputs the GitHub password, e.g. _GH_PASS_CMD="pass github.com"
  • if using 2FA - set _GH_OTPS_CMD to a command that outputs at least two OTP tokens, one per line for the GitHub 2FA, e.g. _GH_OTPS_CMD="oathtool -b --totp <<seed>> -w 1"
  • set _GH_PAT_CMD to a command that outputs your GitHub personal access token, e.g. _GH_PAT_CMD="pass github_pat"

That's it! (phew) - now try pushing to the proxy remote and check if the GitHub Actions workflow run logs are streaming right back:

cd your-original-repo
git commit --allow-empty -m 'test octotail'
git push proxy

Metadata

Release files for octotail 1.0.17

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for octotail 1.0.17
File Size Uploaded Provenance Actions
octotail-1.0.17.tar.gz 22.0 kB Without provenance Details for octotail-1.0.17.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for octotail 1.0.17
File Interpreter ABI Platform Actions
octotail-1.0.17-py3-none-any.whl Python 3 none any Details for octotail-1.0.17-py3-none-any.whl

Total release size: 47.3 kB

Release files / octotail-1.0.17.tar.gz

Download URL octotail-1.0.17.tar.gz
Size 22.0 kB
Tags Source
SHA-256 checksum
How to use checksums
8589d5b59e1525767bde85d36649116a4d7e7583f0189a515ded2d7b5bcc6ea6
BLAKE2b-256 checksum
How to use checksums
3b876c8cbdb2c5f7fe4509b761955dc60f1b86f2aad747f7127dd83ea05cf5f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.4.24

Release files / octotail-1.0.17-py3-none-any.whl

Download URL octotail-1.0.17-py3-none-any.whl
Size 25.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dd2d283e562e8f6899c694c7adfe5494e1387e4d1e40417275e677a92aa8b729
BLAKE2b-256 checksum
How to use checksums
842e24bc00e2c8411a2d5c4cf86e3786ef48a90462b83f57f946c4b2701b3e9d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.4.24

Security for octotail 1.0.17

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page