Project Build Log DevOps · GitHub Actions · Slack

Automating PR approvals with Slack buttons and GitHub Actions

How I built a framework that turns any YAML checklist into a Slack approval flow — one click approves a PR, adds a comment, and fires off a GitHub Actions workflow. No manual steps, no context-switching.

Joshua Burnie March 2026 GitHub Actions AWS Lambda Slack API Python

Overview

Every deployment or release I run has a checklist — environment verified, stakeholders notified, rollback plan confirmed. The problem is those checklists lived in a doc somewhere, disconnected from the actual GitHub PR they were blocking. Engineers had to go find the doc, check the boxes, come back to GitHub, and leave an approval comment. It was tedious and error-prone.

I built this framework to collapse that into a single Slack message. When a checklist needs sign-off, the team gets an interactive Slack message with Approve and Reject buttons. One click does everything: verifies the request, posts a comment on the PR, and triggers whatever GitHub Actions workflow is next in line.

The result: PR approvals that used to take 5–10 minutes of back-and-forth now complete in a single Slack tap, with a full audit trail automatically committed to the repo.

Architecture

Three components, each doing one thing well:

  ┌──────────────────┐      ┌───────────────────────┐      ┌──────────────────┐
  │   Slack App      │ ───▶ │   AWS Lambda          │ ───▶ │   GitHub API     │
  │  (Approve / ✕)   │      │  slack-approval-       │      │  (PR Comments +  │
  │                  │ ◀─── │  handler)              │      │   workflow_dispatch) │
  └──────────────────┘      └───────────────────────┘      └──────────────────┘
                                      │
                             Verifies HMAC-SHA256
                             Slack signature before
                             any action is taken

Slack handles the user-facing interaction. Lambda is the trusted broker — it validates the request, calls GitHub, and updates the Slack message to reflect the outcome. GitHub Actions does the actual deployment work. Each layer is replaceable independently.

The Stack

GitHub Actions

Two workflows: one that validates checklists on PRs, one that fires on Slack approval.

🔔

Slack API

Interactive Block Kit messages with Approve / Reject buttons. HMAC request signing.

λ

AWS Lambda

Python handler that receives Slack payloads, verifies signatures, and calls GitHub.

🌐

API Gateway

HTTP endpoint exposed to Slack's interactivity webhook. Routes all button clicks.

📋

YAML Checklists

Human-readable checklist definitions stored in the repo alongside the workflows.

🔒

HMAC-SHA256

Every incoming request is signature-verified. Timestamps prevent replay attacks.

Setup Guide

01

Create a Slack App

Go to api.slack.com/apps and create a new app named Checklist Approvals. Enable Interactivity & Shortcuts under Features. Add Bot Token Scopes: chat:write and commands. Install the app to your workspace and save the Bot Token and Signing Secret — you'll need both for Lambda.

02

Deploy the Lambda function

Create a new Lambda function in AWS named slack-approval-handler with a Python 3.12 runtime. Copy the code from lambda/lambda_function.py in this repo. Add these environment variables:

# Lambda environment variables SLACK_SIGNING_SECRET = "..." # From Slack App → Basic Information GITHUB_TOKEN = "..." # PAT with repo + workflow scopes

Create an API Gateway HTTP API trigger (open security — Slack signature verification happens inside the function). Copy the generated endpoint URL.

03

Connect Slack to Lambda

In your Slack App settings, go to Interactivity & Shortcuts and set the Request URL to your API Gateway endpoint. Then invite the bot to the channel where approvals will appear:

/invite @Checklist Approvals
04

Add the GitHub Actions workflows

The .github/workflows/ directory contains two workflows. Copy them into your target repository — no changes needed for basic usage.

# checklist.yml — validates on PR open / update on: pull_request: types: [opened, synchronize] # approval.yml — fires when Slack Approve is clicked on: workflow_dispatch: inputs: pr_number: required: true
05

Send an approval message

Trigger a Slack approval message by calling the Slack API. The button value encodes the repo and PR in the format owner:repo:pr_number.

curl -X POST https://slack.com/api/chat.postMessage \ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "channel": "deployments", "text": "Checklist Approval Required", "blocks": [{ "type": "actions", "elements": [{ "type": "button", "text": { "type": "plain_text", "text": "Approve ✅" }, "style": "primary", "action_id": "approve_button", "value": "joshuaburnie:my-repo:42" }] }] }'

End-to-End Flow

What actually happens when someone clicks Approve in Slack:

1️⃣

Button clicked

Slack sends a signed payload to the API Gateway endpoint.

2️⃣

Signature verified

Lambda checks HMAC-SHA256 and rejects requests older than 5 min.

3️⃣

PR comment posted

Lambda calls GitHub API to add an approval comment to the PR.

4️⃣

Workflow triggered

Lambda calls workflow_dispatch on approval.yml.

5️⃣

Slack updated

The original message is updated to reflect Approved / Rejected status.

6️⃣

Artifact saved

Run summary and checklist results are written to artifacts/.

Security

What's Next

The framework is working in production for my security workflows. A few things I'm exploring next:

Multi-approver support — requiring N out of M approvals before the workflow fires, with Slack threads tracking each vote.

Checklist templating — making the YAML checklist definitions richer, with per-step timeouts, owner assignments, and conditional branches.

Slack modal UI — instead of just buttons, opening a Slack modal that shows the full checklist before confirming approval.