diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5c71c8a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,100 @@ +name: Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + packages: write + +jobs: + release: + name: Build and release + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache-dependency-path: go.sum + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: internal/web/ui/package-lock.json + + - name: Build UI + run: make web-build + + - name: Build binaries + run: | + VERSION=${GITHUB_REF_NAME} + LDFLAGS="-s -w -X main.version=${VERSION}" + platforms=( + "linux/amd64" + "linux/arm64" + "darwin/amd64" + "darwin/arm64" + "windows/amd64" + ) + mkdir -p dist + for platform in "${platforms[@]}"; do + GOOS="${platform%/*}" + GOARCH="${platform#*/}" + output="dist/webhix_${GOOS}_${GOARCH}" + if [ "$GOOS" = "windows" ]; then output="${output}.exe"; fi + GOOS=$GOOS GOARCH=$GOARCH go build -ldflags "$LDFLAGS" -o "$output" ./cmd/webhix + done + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: dist/* + generate_release_notes: true + + docker: + name: Build and push Docker image + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a016c40 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,146 @@ +[![RU](https://img.shields.io/badge/lang-ru-blue)](docs/CONTRIBUTING.ru.md) + +# Contributing to Webhix + +Thanks for your interest. This document covers everything you need to get started. + +## Prerequisites + +- Go 1.24+ +- [sqlc](https://sqlc.dev) — regenerating database queries after schema changes +- [goose](https://github.com/pressly/goose) — running migrations manually +- Node.js 20+ — only if touching the UI + +## Project structure + +``` +cmd/webhix/ entry point (main.go) +internal/ + app/ application wiring (dependencies, services, HTTP setup) + cli/ CLI commands (serve, forward) + config/ environment-based configuration + core/ business logic, repository interfaces + domain/ domain types and errors + hub/ SSE event hub + server/ HTTP handlers, routing, middleware + store/ SQLite implementation (sqlc-generated queries) + migrations/ goose migration files + query/ raw SQL queries + sqlc/ generated Go code — do not edit by hand + web/ embedded static assets and UI source + ui/src/ TypeScript/CSS frontend source +pkg/ shared utilities +docs/ documentation +config/ example env files +``` + +## Running locally + +```sh +# Copy example config +cp config/.env.example config/.env + +# Run the server +go run ./cmd/webhix serve + +# Run with a custom address +go run ./cmd/webhix serve --addr :9090 --base-url http://localhost:9090 +``` + +## Running all checks + +```sh +make ci +``` + +This runs formatting, linting, vetting, and tests. All checks must pass before opening a PR. + +Individual commands: + +```sh +make fmt # format Go code +make lint # run golangci-lint +make test # run tests +make web-check # TypeScript check + ESLint + Prettier +``` + +## Branches + +Follow the naming from [docs/branch-patterns.md](docs/branch-patterns.md). + +``` +feature/my-feature +fix/some-bug +refactor/cleanup-handler +``` + +- Branch off `main` +- Keep branches short-lived +- One feature or fix per branch + +## Commits + +Follow the conventions from [docs/commit-patterns.md](docs/commit-patterns.md). + +``` +feat(server): add replay endpoint +fix(store): handle null body on insert +refactor(core): extract token generation +``` + +- English only +- Imperative mood: `add`, `fix`, `remove` +- No period at the end +- No `//nolint` comments — fix the lint issue instead + +## Pull requests + +- PR title follows the same format as commit messages +- Keep PRs small and focused — one thing per PR +- Add a short description of what changed and why +- All CI checks must pass before merging + +## Architecture + +The project follows a layered architecture. Dependencies go in one direction only: + +``` +domain ← store +domain ← core +domain ← server +core ← server +``` + +- `domain` has no dependencies on other internal packages +- `core` defines repository interfaces — it does not import `store` +- `server` depends on `core` interfaces, not on `store` directly +- SQL errors must not leak into `server` — wrap them in `domain` errors at the `store` layer + +## Database changes + +If you change the schema: + +1. Add a migration in `internal/store/migrations/` using goose format +2. Update SQL queries in `internal/store/query/` +3. Regenerate: `sqlc generate` +4. Never edit files in `internal/store/sqlc/` by hand + +## UI changes + +The frontend is in `internal/web/ui/src/` — vanilla TypeScript, no framework. + +```sh +make web-dev # start Vite dev server +make web-build # build and embed into binary +make web-check # lint + type check + prettier +``` + +## Environment + +| Variable | Default | Description | +|----------|---------|-------------| +| `WEBHIX_BASE_URL` | `http://localhost:8080` | Public base URL for generated endpoint links | +| `WEBHIX_ADDR` | `:8080` | Listen address | +| `WEBHIX_DB_PATH` | `./data` | SQLite database directory | +| `WEBHIX_PASSWORD` | — | Basic auth password | +| `WEBHIX_SECRET_KEY` | — | API secret key (Bearer / X-Webhix-Key) | diff --git a/README.md b/README.md index bfa364d..5831bc4 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,56 @@ # Webhix -[![RU](https://img.shields.io/badge/lang-ru-blue)](docs/README.ru.md) [![Contributing](https://img.shields.io/badge/contributing-guide-brightgreen)](CONTRIBUTING.md) +[![Release](https://img.shields.io/github/v/release/gaisbax/webhix)](https://github.com/gaisbax/webhix/releases) +[![License](https://img.shields.io/badge/license-AGPL--3.0-blue)](LICENSE) +[![Go Report Card](https://goreportcard.com/badge/github.com/gaisbax/webhix)](https://goreportcard.com/report/github.com/gaisbax/webhix) +[![Docker](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/gaisbax/webhix/pkgs/container/webhix) +[![RU](https://img.shields.io/badge/lang-ru-blue)](docs/README.ru.md) +[![Contributing](https://img.shields.io/badge/contributing-guide-brightgreen)](CONTRIBUTING.md) Self-hosted webhook inspector. Single binary, SQLite, no external dependencies. -webhook.site is the go-to tool for debugging webhooks, but it sends your data to someone else's server. Stripe payloads, OAuth tokens, PII — all of it leaves your network. A lot of companies block it outright for that reason. Webhix runs on your own infrastructure, stores everything locally, and stays out of your way. +webhook.site is the go-to tool for debugging webhooks, but it sends your data to someone else's server. Stripe payloads, OAuth tokens, PII — all of it leaves your network. A lot of companies block it outright for that reason. Webhix runs on your own infrastructure and stores everything locally. -## What it does +![Webhix UI](docs/screenshot.png) -You create an endpoint, point your webhook source at it, and watch requests come in. Every request is captured in full — headers, body, query params, IP, timestamp, content type, size. The UI updates live without a page refresh. +## Features -Beyond just inspecting requests, you can: +- 📡 Capture any HTTP method — headers, body, query params, IP, timestamp, content type, size +- 🔴 Live UI updates via SSE — no page refresh needed +- 🪞 Replay any request with one click +- 🎭 Custom responses — configure status, headers, and body (lightweight mock server) +- 🔁 CLI forwarding to localhost: `webhix forward --to localhost:3000` +- 📋 Export as curl — copy any request as a runnable command +- 🔍 Full-text search and filter by HTTP method +- 🔒 Basic auth out of the box +- 🐳 Docker, Compose, or standalone binary +- 💾 SQLite by default — no Redis or Postgres required -- **Replay** any captured request with one click -- **Custom responses** — configure the status code, headers, and body your endpoint returns to senders (useful as a lightweight mock server) -- **CLI forwarding** — pipe incoming requests to a local port: `webhix forward --to localhost:3000` -- **Export as curl** — copy any request as a runnable curl command -- **Search and filter** — filter requests by text or HTTP method +## Why not webhook.site / smee.io / webhook-tester? + +| | Webhix | webhook.site (self-hosted) | smee.io | tarampampam/webhook-tester | +| --------------- | ------------- | ----------------------------- | -------------- | -------------------------- | +| Self-hosted | ✅ | ✅ | ❌ | ✅ | +| Single binary | ✅ | ❌ PHP + Composer + MySQL | ❌ | ❌ Redis or fs driver | +| Request history | ✅ | ✅ | ❌ | ✅ | +| Live UI | ✅ | ✅ | ❌ | ✅ | +| Replay | ✅ | ❌ | ❌ | ❌ | +| CLI forwarding | ✅ built-in | ❌ | ✅ only this | ❌ needs ngrok | +| Custom responses| ✅ | ❌ | ❌ | ❌ | + +Webhix is the only tool combining single-binary deployment, request replay, and custom responses — no Redis, no PHP, no external tunnel services. ## Quick start ### Binary ```sh -curl -fsSL https://webhix.dev/install.sh | sh +curl -fsSL https://webhix.online/install.sh | sh webhix serve --base-url https://hooks.yourdomain.com ``` +Or download manually from [releases](https://github.com/gaisbax/webhix/releases/latest). + ### Docker ```sh diff --git a/docs/CONTRIBUTING.ru.md b/docs/CONTRIBUTING.ru.md new file mode 100644 index 0000000..c48999d --- /dev/null +++ b/docs/CONTRIBUTING.ru.md @@ -0,0 +1,146 @@ +[![EN](https://img.shields.io/badge/lang-en-gray)](../CONTRIBUTING.md) + +# Как контрибьютить в Webhix + +Спасибо за интерес к проекту. Здесь всё что нужно чтобы начать. + +## Что нужно установить + +- Go 1.24+ +- [sqlc](https://sqlc.dev) — для регенерации запросов к БД после изменений схемы +- [goose](https://github.com/pressly/goose) — для ручного запуска миграций +- Node.js 20+ — только если меняете UI + +## Структура проекта + +``` +cmd/webhix/ точка входа (main.go) +internal/ + app/ сборка приложения (зависимости, сервисы, HTTP) + cli/ CLI-команды (serve, forward) + config/ конфигурация через переменные окружения + core/ бизнес-логика, интерфейсы репозиториев + domain/ доменные типы и ошибки + hub/ SSE event hub + server/ HTTP-хендлеры, роутинг, middleware + store/ SQLite-реализация (sqlc-сгенерированные запросы) + migrations/ goose-миграции + query/ сырые SQL-запросы + sqlc/ сгенерированный Go-код — не редактировать вручную + web/ встроенные статические файлы и исходники UI + ui/src/ TypeScript/CSS фронтенд +pkg/ общие утилиты +docs/ документация +config/ примеры .env файлов +``` + +## Запуск локально + +```sh +# Скопируйте пример конфига +cp config/.env.example config/.env + +# Запустите сервер +go run ./cmd/webhix serve + +# С кастомным адресом +go run ./cmd/webhix serve --addr :9090 --base-url http://localhost:9090 +``` + +## Запуск всех проверок + +```sh +make ci +``` + +Запускает форматирование, линтинг, vet и тесты. Все проверки должны проходить до открытия PR. + +Отдельные команды: + +```sh +make fmt # форматирование Go кода +make lint # запуск golangci-lint +make test # запуск тестов +make web-check # TypeScript проверка + ESLint + Prettier +``` + +## Ветки + +Следуйте нотации из [docs/branch-patterns.md](branch-patterns.md). + +``` +feature/my-feature +fix/some-bug +refactor/cleanup-handler +``` + +- Ветвитесь от `main` +- Держите ветки короткими +- Одна фича или фикс на ветку + +## Коммиты + +Следуйте конвенции из [docs/commit-patterns.md](commit-patterns.md). + +``` +feat(server): add replay endpoint +fix(store): handle null body on insert +refactor(core): extract token generation +``` + +- Только английский язык +- Повелительное наклонение: `add`, `fix`, `remove` +- Без точки в конце +- Никаких `//nolint` комментариев — исправьте причину lint-ошибки + +## Pull request-ы + +- Заголовок PR следует тому же формату что и коммиты +- Держите PR маленькими и сфокусированными — одна вещь на PR +- Добавьте короткое описание что изменилось и почему +- Все CI-проверки должны проходить до мержа + +## Архитектура + +Проект следует строгой слоистой архитектуре. Зависимости идут только в одном направлении: + +``` +domain ← store +domain ← core +domain ← server +core ← server +``` + +- `domain` не зависит от других внутренних пакетов +- `core` определяет интерфейсы репозиториев — не импортирует `store` +- `server` зависит только от интерфейсов `core`, не от `store` напрямую +- SQL-ошибки не должны утекать в `server` — оборачивайте их в `domain`-ошибки на уровне `store` + +## Изменения в БД + +Если меняете схему: + +1. Добавьте миграцию в `internal/store/migrations/` в формате goose +2. Обновите SQL-запросы в `internal/store/query/` +3. Регенерируйте: `sqlc generate` +4. Никогда не редактируйте файлы в `internal/store/sqlc/` вручную + +## Изменения в UI + +Фронтенд находится в `internal/web/ui/src/` — vanilla TypeScript, без фреймворков. + +```sh +make web-dev # запустить Vite dev server +make web-build # собрать и встроить в бинарник +make web-check # lint + type check + prettier +``` + +## Переменные окружения + +| Переменная | По умолчанию | Описание | +| ------------------- | ----------------------- | ------------------------------------------ | +| `WEBHIX_BASE_URL` | `http://localhost:8080` | Публичный URL для генерации ссылок | +| `WEBHIX_ADDR` | `:8080` | Адрес для прослушивания | +| `WEBHIX_DB_PATH` | `./data` | Директория SQLite базы данных | +| `WEBHIX_PASSWORD` | — | Пароль Basic Auth | +| `WEBHIX_SECRET_KEY` | — | API секретный ключ (Bearer / X-Webhix-Key) | diff --git a/docs/README.ru.md b/docs/README.ru.md index 363da7b..6d79c98 100644 --- a/docs/README.ru.md +++ b/docs/README.ru.md @@ -1,31 +1,54 @@ # Webhix +[![Release](https://img.shields.io/github/v/release/gaisbax/webhix)](https://github.com/gaisbax/webhix/releases) +[![License](https://img.shields.io/badge/license-AGPL--3.0-blue)](../LICENSE) +[![Go Report Card](https://goreportcard.com/badge/github.com/gaisbax/webhix)](https://goreportcard.com/report/github.com/gaisbax/webhix) +[![Docker](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/gaisbax/webhix/pkgs/container/webhix) [![EN](https://img.shields.io/badge/lang-en-gray)](../README.md) +[![Contributing](https://img.shields.io/badge/contributing-guide-brightgreen)](CONTRIBUTING.ru.md) Self-hosted инспектор вебхуков. Один бинарник, SQLite, никаких внешних зависимостей. -webhook.site удобен, но отправляет все данные на чужой сервер. Stripe payload-ы, OAuth токены, персональные данные - всё это уходит из вашей сети. Многие компании блокируют его по этой причине. Webhix работает на вашей инфраструктуре, хранит всё локально и не мешает работе. +webhook.site удобен, но отправляет все данные на чужой сервер. Stripe payload-ы, OAuth-токены, персональные данные — всё это уходит из вашей сети. Многие компании блокируют его по корпоративной политике безопасности. Webhix работает на вашей инфраструктуре и хранит всё локально. -## Что умеет +![Webhix UI](screenshot.png) -Создаёте endpoint, направляете на него вебхуки и смотрите что приходит. Каждый запрос сохраняется полностью - заголовки, тело, query параметры, IP, время, content-type, размер. Интерфейс обновляется без перезагрузки страницы. +## Возможности -Помимо просмотра: +- 📡 Захват любых HTTP-методов — заголовки, тело, query-параметры, IP, время, content-type, размер +- 🔴 Обновление UI в реальном времени через SSE — без перезагрузки страницы +- 🪞 Replay любого запроса одним кликом +- 🎭 Кастомные ответы — настройте статус, заголовки и тело (лёгкий mock-сервер) +- 🔁 Forwarding через CLI: `webhix forward --to localhost:3000` +- 📋 Экспорт как curl — скопируйте любой запрос готовой командой +- 🔍 Полнотекстовый поиск и фильтр по HTTP-методу +- 🔒 Базовая авторизация из коробки +- 🐳 Docker, Compose или standalone бинарник +- 💾 SQLite по умолчанию — Redis и Postgres не нужны -- **Replay** - повторить любой запрос одним кликом, можно с изменениями -- **Кастомные ответы** - настроить статус код, заголовки и тело ответа вашего endpoint-а (удобно как лёгкий mock-сервер) -- **Forwarding через CLI** - проксировать входящие запросы на локальный порт: `webhix forward --to localhost:3000` -- **Экспорт** - скопировать любой запрос как готовую команду curl или HTTPie +## Почему не webhook.site / smee.io / webhook-tester? + +| | Webhix | webhook.site (self-hosted) | smee.io | tarampampam/webhook-tester | +| ---------------- | -------------- | ------------------------------ | --------------- | --------------------------- | +| Self-hosted | ✅ | ✅ | ❌ | ✅ | +| Один бинарник | ✅ | ❌ PHP + Composer + MySQL | ❌ | ❌ Redis или fs driver | +| История запросов | ✅ | ✅ | ❌ | ✅ | +| Живой UI | ✅ | ✅ | ❌ | ✅ | +| Replay | ✅ | ❌ | ❌ | ❌ | +| CLI forwarding | ✅ встроен | ❌ | ✅ только это | ❌ нужен ngrok | +| Кастомные ответы | ✅ | ❌ | ❌ | ❌ | ## Быстрый старт ### Бинарник ```sh -curl -fsSL https://webhix.dev/install.sh | sh +curl -fsSL https://webhix.online/install.sh | sh webhix serve --base-url https://hooks.yourdomain.com ``` +Или скачайте вручную со страницы [releases](https://github.com/gaisbax/webhix/releases/latest). + ### Docker ```sh @@ -57,23 +80,34 @@ URL endpoint-ов формируется по шаблону `https:// ## Авторизация -По умолчанию однопользовательский режим. Пароль задаётся через env: +Авторизация обязательна. Задайте хотя бы одно из: ```sh +# Пароль для входа через браузер (Basic Auth) WEBHIX_PASSWORD=yourpassword webhix serve + +# Секретный ключ для API и CLI (заголовок Bearer / X-Webhix-Key) +WEBHIX_SECRET_KEY=yourkey webhix serve + +# Оба сразу +webhix serve --password yourpassword --secret-key yourkey ``` +URL для приёма вебхуков (`/r/`) всегда публичны — авторизация там не нужна. + ## Обратный прокси -Работает за Caddy, Nginx, Traefik. Автоматически читает заголовки `X-Forwarded-*`. Укажите `WEBHIX_BASE_URL` чтобы совпадал с вашим публичным доменом. +Работает за Caddy, Nginx, Traefik. Автоматически читает заголовки `X-Forwarded-*`. Укажите `--base-url` или `WEBHIX_BASE_URL` чтобы совпадал с вашим публичным доменом. ## Конфигурация -| Env переменная | По умолчанию | Описание | -| -------------- | ------------ | -------- | -| `WEBHIX_BASE_URL` | `http://localhost:8080` | Публичный URL для генерации ссылок на endpoint-ы | -| `WEBHIX_ADDR` | `:8080` | Адрес для прослушивания (например `0.0.0.0:9000`) | -| `WEBHIX_DB_PATH` | `./data` | Путь к директории с SQLite базой данных | +| Env переменная | По умолчанию | Описание | +| --------------------- | ---------------------- | ------------------------------------------------- | +| `WEBHIX_BASE_URL` | `http://localhost:8080`| Публичный URL для генерации ссылок на endpoint-ы | +| `WEBHIX_ADDR` | `:8080` | Адрес для прослушивания (например `0.0.0.0:9000`) | +| `WEBHIX_DB_PATH` | `./data` | Путь к директории с SQLite базой данных | +| `WEBHIX_PASSWORD` | — | Пароль Basic Auth | +| `WEBHIX_SECRET_KEY` | — | API секретный ключ (Bearer / X-Webhix-Key) | ## Технические детали @@ -81,7 +115,7 @@ WEBHIX_PASSWORD=yourpassword webhix serve - SQLite по умолчанию, внешняя база не нужна - UI встроен в бинарник через `go:embed` - Работает на Linux, macOS, Windows (amd64 + arm64) -- Потребление памяти в простое - менее 50 МБ +- Потребление памяти в простое — менее 50 МБ ## Roadmap @@ -89,17 +123,17 @@ WEBHIX_PASSWORD=yourpassword webhix serve - Мультипользовательский режим с базовым RBAC - Верификация подписи вебхуков (в стиле Stripe, GitHub) -- Валидация схемы +- Валидация схемы запросов - Уведомления о новых запросах (Slack, Telegram, Discord) - Опциональная поддержка Postgres - Авто-HTTPS через Let's Encrypt (без обратного прокси) ### v0.3+ -- Tunnel режим - подключение к управляемому relay для получения публичного URL без сервера +- Tunnel-режим — подключение к управляемому relay для получения публичного URL без сервера ## Лицензия [AGPL-3.0](../LICENSE). Self-hosted использование всегда бесплатно и открыто. -Если хотите запустить Webhix как сетевой сервис с закрытыми изменениями - свяжитесь с нами по вопросу коммерческой лицензии. +Если хотите запустить Webhix как сетевой сервис с закрытыми изменениями — свяжитесь с нами по вопросу коммерческой лицензии.