RepoPilotOpen in app →

appleboy/gorush

A push notification server written in Go (Golang).

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3w ago
  • 7 active contributors
  • MIT licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Single-maintainer risk — top contributor 93% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/appleboy/gorush)](https://repopilot.app/r/appleboy/gorush)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/appleboy/gorush on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: appleboy/gorush

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/appleboy/gorush shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 3w ago
  • 7 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Single-maintainer risk — top contributor 93% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live appleboy/gorush repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/appleboy/gorush.

What it runs against: a local clone of appleboy/gorush — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in appleboy/gorush | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | Last commit ≤ 53 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>appleboy/gorush</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of appleboy/gorush. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/appleboy/gorush.git
#   cd gorush
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of appleboy/gorush and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "appleboy/gorush(\\.git)?\\b" \\
  && ok "origin remote is appleboy/gorush" \\
  || miss "origin remote is not appleboy/gorush (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 53 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~23d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/appleboy/gorush"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

gorush is a high-performance push notification server written in Go that delivers messages to iOS (via APNs), Android (via FCM), and Huawei devices through a REST API and CLI. It handles notification queueing, batching, and delivery with support for multiple backend storage engines (Redis, BuntDB, BadgerDB, LevelDB) and message queues (NATS, NSQ, Redis Streams). Modular monorepo structure: app/ contains core sender logic (config.go, sender.go, worker.go for goroutine-based workers), core/ abstracts storage and queue interfaces (core.go, storage.go, queue.go), config/ handles YAML parsing via Viper, and platform-specific logic branches for APNs (sideshow/apns2), FCM (appleboy/go-fcm), and HMS (appleboy/go-hms-push). The Gin HTTP server wraps this in a REST API.

👥Who it's for

Backend engineers and DevOps teams who need to operate a self-hosted push notification infrastructure for mobile apps at scale, without dependency on third-party notification services like Firebase Cloud Messaging alone.

🌱Maturity & risk

Production-ready. The project shows active maintenance (Go 1.25.9, recent security scanning via Trivy, comprehensive CI/CD with GitHub Actions for testing, linting, and Docker builds), has 267K lines of Go code with test coverage tracked via codecov, and follows semantic versioning (currently v1.18.9). Continuous integration is configured with .golangci.yml and multiple workflow definitions.

Low-to-moderate risk for adoption. The dependency graph is substantial (Firebase Admin SDK, gRPC, Redis client, multiple queue backends) but all are mature packages. Single-maintainer concern (appleboy) is typical for open-source, mitigated by Docker support and stable API surface. No breaking changes visible in recent releases, though upgrading queue backends (NATS, NSQ) requires coordination.

Active areas of work

Active security scanning (Trivy in CI), dependency updates via Dependabot, and Docker image maintenance. The .github/workflows/ shows testing.yml (linting + unit tests), docker.yaml (multi-platform builds), and goreleaser.yml (binary releases). No major feature work is evident from file structure, suggesting focus on stability and security.

🚀Get running

Clone the repo, install Go 1.25.9+, and build: git clone https://github.com/appleboy/gorush.git && cd gorush && make build. Alternatively, docker-compose up (docker-compose.yml is present). Or download a prebuilt binary from releases: wget https://github.com/appleboy/gorush/releases/download/v1.18.9/gorush-1.18.9-linux-amd64.

Daily commands: Start server: ./gorush (listens on port 8088 by default). Send notification via REST: curl -X POST http://localhost:8088/api/push -H 'Content-Type: application/json' -d '{"notifications":[{"tokens":["device_token"],"platform":2,"title":"Test","message":"Hello"}]}'. See Makefile for development targets: make help lists build, test, and lint commands.

🗺️Map of the codebase

  • app/sender.go: Core notification delivery logic for all platforms; orchestrates APNs, FCM, and HMS SDK calls
  • app/worker.go: Goroutine worker pool that processes queued notifications with configurable concurrency
  • core/storage.go: Interface-based abstraction for persistent storage; pluggable implementations for Redis, BadgerDB, BuntDB, LevelDB
  • core/queue.go: Message queue abstraction layer; supports NATS, NSQ, Redis Streams, in-memory with fallbacks
  • config/config.go: Viper-based YAML config parsing for platform credentials, queue/storage backends, TLS, and logging
  • app/options.go: Functional options pattern for configuring gorush at runtime; centralizes all tunable parameters
  • .github/workflows/testing.yml: CI pipeline: runs golangci-lint, unit tests, and codecov; defines Go version constraints

🛠️How to make changes

Adding a new platform: Extend app/sender.go and core/storage.go interfaces, add SDK in separate module (e.g., appleboy/go-yourplatform). Fixing bugs: Look in app/ for sender/worker logic, config/ for parsing issues, core/ for queue/storage problems. New features: Check core/queue.go and core/storage.go for existing abstractions before adding. Tests: Co-locate *_test.go files (e.g., app/sender_test.go) using testify assertions (seen in go.mod).

🪤Traps & gotchas

APNs certificates: Must provide valid .p8 (modern) or .p12 (legacy) files in certificate/ directory; test certs (authkey-valid.p8, certificate-valid.pem) are included but not for production. Queue/Storage backend mismatch: If config specifies Redis queue but uses BuntDB storage, initialization order in core.go matters—read core/core_test.go to understand startup. Goroutine limits: app/worker.go spawns workers per config; no auto-scaling; set worker_num carefully for your system. TLS in Docker: docker/Dockerfile uses scratch base; cert paths must be absolute or mounted volumes. gRPC optional: grpc-ecosystem/go-grpc-middleware is in go.mod but gRPC is not required for REST-only deployments.

💡Concepts to learn

  • Token Bucket Rate Limiting — gorush must throttle push delivery to avoid overwhelming APNs, FCM, and device networks; understanding rate limiting is essential for configuring worker_num and queue backend capacity
  • Goroutine Worker Pool — app/worker.go uses a fixed pool of goroutines to process queued notifications concurrently; tuning this pool size directly impacts throughput and memory usage in production
  • Interface-Based Storage Abstraction — core/storage.go defines Storage and QueueMessage interfaces allowing pluggable backends (Redis, BuntDB, BadgerDB); swapping backends at runtime requires only config changes, not code
  • APNs Binary Protocol and JWT Tokens — iOS delivery requires either p8 certificates (modern, JWT-based) or p12 (legacy); gorush delegates to sideshow/apns2 but misconfigurations here are the #1 production issue
  • FCM Multicast Messages — gorush batches Android notifications into FCM multicast requests to reduce API calls; understanding batch size limits (500 tokens per request in FCM) is critical for performance tuning
  • gRPC vs REST Trade-offs — gorush exposes both Gin REST API and optional gRPC endpoints (grpc-ecosystem/go-grpc-middleware in deps); choosing which client to use affects latency, protocol overhead, and language support
  • Graceful Shutdown and Backpressure — appleboy/graceful in go.mod enables in-flight notification flushing before shutdown; misconfiguring timeouts causes lost notifications or dropped connections in Kubernetes/Docker environments
  • google/firebase-admin-go — Official Firebase Admin SDK for Go; gorush uses firebase.google.com/go/v4 for FCM, can be used standalone as an alternative
  • sideshow/apns2 — Pure Go APNs library; gorush wraps this for iOS delivery; understanding apns2 internals helps debug APNs-specific issues
  • golang-queue/queue — Abstract queue interface that gorush depends on; provides middleware and multiple backend implementations (NATS, NSQ, Redis Streams)
  • appleboy/flutter-gorush — Demo Flutter app referenced in README; shows client-side integration patterns and how to consume gorush REST API from mobile apps
  • centrifugal/centrifugo — Alternative real-time messaging server in Go with similar deployment patterns; useful for understanding gorush's architectural choices around worker pools and storage abstraction

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for core/queue.go message queue abstraction

The repo supports multiple queue backends (Redis, NATS, NSQ, BuntDB, LevelDB) via golang-queue but core/queue.go lacks integration tests. Currently only core/core_test.go exists. New contributors should add queue-specific integration tests to verify each backend works correctly with the gorush sender, which is critical for production reliability.

  • [ ] Create core/queue_test.go with test cases for each queue backend
  • [ ] Add Docker Compose test environment in docker-compose.yml for Redis/NATS/NSQ services
  • [ ] Test queue.Push(), queue.Pop(), and error handling for each backend implementation
  • [ ] Add GitHub Actions workflow step in .github/workflows/testing.yml to run integration tests with docker-compose
  • [ ] Verify message integrity and ordering across queue backends

Add missing unit tests for app/options.go configuration validation

app/options_test.go exists but is likely minimal. The app/options.go file handles critical configuration for APNs, FCM, HMS providers. Missing tests for validation edge cases (invalid certificates, malformed configs, missing credentials) could allow invalid configurations to reach production.

  • [ ] Expand app/options_test.go to test all Option setter functions with valid/invalid inputs
  • [ ] Add test cases for certificate validation paths (app/options.go likely validates .p8/.p12 files)
  • [ ] Test token/key validation for APNs, FCM, and HMS providers
  • [ ] Add table-driven tests for configuration edge cases (empty strings, nil values, path traversal attempts)
  • [ ] Verify test coverage reaches >90% for app/options.go

Add security-focused linting rules to .golangci.yml and document in CLAUDE.md

The repo has .golangci.yml but likely lacks security-specific linters critical for a notification server handling credentials/tokens. Gosec, Revive security rules, and other analyzers should be enabled. CLAUDE.md exists but doesn't document security contribution standards.

  • [ ] Enable gosec linter in .golangci.yml with custom rules for crypto usage and credential handling
  • [ ] Enable revive and add rules for error handling (particularly around secret logging in logrus/zerolog calls)
  • [ ] Add a 'Security Checklist' section to CLAUDE.md documenting: no credentials in logs, no hardcoded secrets, safe crypto usage
  • [ ] Run updated linter across entire codebase and create follow-up issues for any violations found
  • [ ] Update .github/workflows/codeql.yaml to include gosec scan as explicit step (if not already present)

🌿Good first issues

  • Add integration tests for BuntDB storage backend: core/storage.go has interfaces for BadgerDB and LevelDB, but no test coverage for BuntDB (tidwall/buntdb in go.mod). Write tests in core/core_test.go that exercise BuntDB queue operations (Enqueue, Dequeue) to match existing patterns.
  • Document config.yml schema with YAML comments: config/testdata/config.yml exists but lacks inline documentation. Add comments explaining each top-level key (ios, android, queue, storage, log) with type hints and default values; users currently must read config/config.go struct tags.
  • Add Prometheus metrics for queue depth and worker utilization: prometheus/client_golang is in go.mod and metrics are exported in app/sender.go, but gauge metrics for current queue size and active workers are missing. Add two Prometheus gauges in core/queue.go and app/worker.go to expose queue length and goroutine count.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 97f0a39 — fix(deps): bump Go from 1.25.0 to 1.25.9 to patch stdlib CVEs (appleboy)
  • 0955720 — ci(docker): add Trivy vulnerability scan before pushing images (appleboy)
  • 2f58f82 — fix(docker): upgrade base packages to patch OpenSSL CVE-2026-28390 (appleboy)
  • 1734f80 — ci(deps): bump codecov/codecov-action from v5 to v6 (appleboy)
  • 3187b88 — fix(deps): bump OpenTelemetry packages from v1.42.0 to v1.43.0 (appleboy)
  • 05d41f6 — refactor(config): replace manual viper mapping with Unmarshal (#870) (appleboy)
  • f193151 — fix(deps): bump vulnerable dependencies to patched versions (appleboy)
  • e189f99 — fix(router): resolve memory leak from uncancelled contexts in async mode (#866) (savinnorse)
  • d50915d — fix(deps): bump google.golang.org/grpc to v1.79.3 (#868) (appleboy)
  • 03c17fd — fix(config): redact sensitive fields in /api/config response (#865) (appleboy)

🔒Security observations

  • High · Outdated Go Version in go.mod — go.mod. The project specifies 'go 1.25.9' which does not exist. The latest stable Go version is 1.23.x. This suggests either a typo or use of a non-existent version, which could lead to unexpected behavior or inability to build with standard tooling. Fix: Update go.mod to use a valid Go version (e.g., 'go 1.23' or 'go 1.22'). Verify the actual Go version used in CI/CD pipelines.
  • High · Test Certificates Committed to Repository — certificate/ directory (certificate/localhost.key, certificate/certificate-valid.pem, certificate/authkey-valid.p8, etc.). Multiple certificate and key files are committed to the repository (localhost.key, localhost.cert, authkey files, certificate.p12, certificate.pem). While marked as test certificates, private keys should never be committed to version control even for testing purposes. Fix: Remove all private key files from the repository. Add certificate/ directory to .gitignore. Use environment variables or secure secret management systems for certificate/key distribution. Generate test certificates locally during test execution.
  • High · Potential Unencrypted Credential Storage — config/testdata/config.yml, docker-compose.yml, app/config.go. The codebase includes configuration files (config/testdata/) and environment variable handling for sensitive data (GORUSH_CORE_QUEUE_NUM seen in docker-compose). No encryption mechanism is evident for at-rest credential storage. Fix: Implement encrypted secret storage. Use external secret management (AWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets). Never store credentials in plaintext configuration files. Rotate all exposed credentials.
  • Medium · Exposed Ports in Docker Configuration — docker-compose.yml (ports 8088, 9000). The docker-compose.yml exposes both port 8088 (HTTP API) and port 9000 (likely metrics/gRPC) without any authentication mechanism visible or rate limiting configuration shown. Fix: Implement API authentication (API keys, OAuth2, mTLS). Add rate limiting and DDoS protection. Use a reverse proxy/API gateway. Restrict port exposure with firewall rules or network policies. Consider using environment-specific configurations.
  • Medium · Dependency on Replaced Package — go.mod (replace directive for go-hms-push). The go.mod file contains a replace directive for 'github.com/msalihkarakasli/go-hms-push' pointing to a third-party fork. This increases supply chain risk and could be a point of vulnerability if the fork is unmaintained. Fix: Verify the security posture of the replacement package. Consider contributing fixes upstream instead of using forks. Implement Software Composition Analysis (SCA) scanning. Pin to specific commit hashes for forks.
  • Medium · Missing Security Headers Configuration — app/sender.go, main.go, core/core.go. No evidence of security headers configuration (HSTS, CSP, X-Frame-Options, etc.) in the Gin framework setup. The application serves push notifications over HTTP which may lack proper security headers. Fix: Add middleware for security headers in Gin. Implement HSTS, CSP, X-Content-Type-Options, X-Frame-Options. Force HTTPS in production. Use gin-contrib/cors with restricted origins.
  • Medium · Multiple Storage Backends Without Encryption Evidence — core/storage.go, config/config.go. The codebase supports multiple storage backends (Redis, BoltDB, LevelDB, BadgerDB, BuntDB, Storm) but no explicit encryption configuration is visible for data at rest. Fix: Enforce encryption for all storage backends. Use encrypted connection strings for Redis. Enable encryption-at-rest for BadgerDB. Document encryption requirements for each backend type.
  • Low · Logging Configuration May Expose Sensitive Data — logx/log.go, logx/log_. Application uses zerolog and logrus without visible configuration to prevent logging of sensitive information (API keys, tokens, user data). Log files are created in logx/log/ directory without apparent access controls. Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · appleboy/gorush — RepoPilot