mirror of
https://github.com/taigrr/github-to-signal.git
synced 2026-04-02 03:09:09 -07:00
4.1 KiB
4.1 KiB
Agent Guide for github-to-signal
HTTP server that receives GitHub webhook events and forwards them as Signal messages via signal-cli.
Commands
# Build
GOWORK=off go build -o github-to-signal .
# Test
GOWORK=off go test .
# Run (requires config.toml)
./github-to-signal
Note: This repo may not be in a parent go.work workspace. Use GOWORK=off to ensure commands work standalone.
Project Structure
.
├── main.go # Entry point, HTTP server, event handlers
├── config.go # Configuration loading (TOML + env vars)
├── filter.go # Event filtering logic
├── filter_test.go # Tests for event filtering
├── format.go # Message formatting for each event type
├── config.example.toml
└── deploy/ # Systemd services and nginx config
All source files are in the root directory (single main package, no subdirectories).
Configuration
Configuration via config.toml or environment variables with GH2SIG_ prefix:
| Config Key | Env Variable | Description |
|---|---|---|
webhook_secret |
GH2SIG_WEBHOOK_SECRET |
GitHub webhook secret |
listen_addr |
GH2SIG_LISTEN_ADDR |
Server address (default :9900) |
signal_url |
GH2SIG_SIGNAL_URL |
signal-cli JSON-RPC endpoint |
signal_account |
GH2SIG_SIGNAL_ACCOUNT |
Phone number for signal-cli |
signal_recipient |
GH2SIG_SIGNAL_RECIPIENT |
Recipient UUID for DMs |
signal_group_id |
GH2SIG_SIGNAL_GROUP_ID |
Group ID (overrides recipient) |
events |
GH2SIG_EVENTS |
Comma-separated event filter |
Configuration is loaded using jety library.
Code Patterns
Event Handlers
Each GitHub event type has:
- A handler method on
notifierstruct inmain.go - A
format*function informat.gothat returns the Signal message
Handler pattern:
func (n *notifier) onEventName(ctx context.Context, _ string, _ string, event *github.EventType) error {
if !n.filter.Allowed("event_name", event.GetAction()) {
return nil
}
n.send(ctx, formatEventName(event))
return nil
}
Event Filtering
EventFilter in filter.go supports:
- Empty filter = allow all events
"event"= all actions of that event type"event:action"= specific action only
Two-level check:
EventEnabled(event)— used at registration time to skip registering handlersAllowed(event, action)— checked at runtime for action-level filtering
Message Formatting
All format* functions in format.go:
- Return a string (empty string = no message sent)
- Use
[repo] user action ...prefix format - Include relevant URLs
- Truncate bodies with
truncate()helper
Dependencies
cbrgm/githubevents— GitHub webhook event parsing and routinggoogle/go-github— GitHub API typestaigrr/signalcli— signal-cli JSON-RPC clienttaigrr/jety— Configuration (TOML/JSON/YAML/env)
Adding New Event Types
- Add handler method in
main.gofollowing existing pattern - Register handler in
main()withEventEnabledcheck - Add
format*function informat.go - Add event name to filter docs in
config.example.toml
Testing
Only filter_test.go exists — table-driven tests for EventFilter.
GOWORK=off go test -v .
HTTP Endpoints
| Path | Method | Description |
|---|---|---|
/webhook |
POST | GitHub webhook receiver |
/health |
GET | Health check (returns ok) |
Deployment
Systemd services in deploy/:
signal-cli-bot.service— runs signal-cli daemongithub-to-signal.service— runs this server (depends on signal-cli)github-to-signal.nginx.conf— nginx reverse proxy config
The server expects signal-cli to be running on 127.0.0.1:8081.
Gotchas
- GOWORK: May need
GOWORK=offif a parentgo.workexists - signal-cli port: Default in code is
8080, but deployment uses8081to avoid conflicts - Workflow runs: Only notifies on
completedaction, ignoresrequested/in_progress - Empty message: Returning
""from a formatter skips sending (used by workflow_run filter)