Skip to content

Xalior/GitTaskFanOut

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”€ Git Task Fan Out

A lightweight webhook router that receives incoming webhooks on unique endpoints and fans them out to multiple destinations in parallel. Designed for self-hosted Git platforms (Gitea, GitLab) with signature verification support for those platforms and GitHub. It forwards raw requests (headers + body) so it may work with other webhook sources too, but that's not tested or officially supported.

πŸ“‹ Changelog


πŸ€” Why?

  • πŸ”— Single ingress point β€” expose one webhook URL instead of many
  • πŸ“‘ Fan out to multiple targets β€” CI, chat notifications, monitoring, etc. all from one hook
  • 🏠 Configure routing outside your Git host β€” no need to add N webhooks per repo
  • πŸ”’ Keep internal services private β€” only the fanout server needs to be reachable

πŸš€ Quick Start

With Docker Compose

# Clone and start
git clone https://github.com/Xalior/GitTaskFanOut.git && cd GitTaskFanOut
docker compose up -d

# Open http://localhost:6175 β€” register an admin account on first run

Without Docker

# Prerequisites: Node.js 22+, pnpm
pnpm install
pnpm dev        # development (http://localhost:6175)
pnpm build && pnpm start   # production

βš™οΈ Configuration

All config lives in the data/ directory as INI files:

File Purpose
routes.ini Webhook routes (managed via UI)
users.ini Admin user accounts (created via UI)
auth.ini Optional pepper for password hashing
theme.css Optional theme CSS (replaces Bootstrap entirely)

πŸ”‘ Environment Variables

Variable Default Description
SESSION_SECRET dev default Session encryption key (min 32 chars)
AUTH_PEPPER (none) Appended to passwords before bcrypt hashing
PORT 6175 Server listen port
NODE_ENV development Set to production for prod
BIND_ADDRESS 0.0.0.0 Docker host bind IP (e.g. 172.17.0.1 to restrict to Docker bridge)
SMTP_URL (none) SMTP connection URL for password reset emails
SMTP_FROM noreply@localhost From address for password reset emails

πŸ”’ Password Pepper

Set via AUTH_PEPPER env var (recommended) or in data/auth.ini:

[_meta]
pepper = your-random-string-here

πŸ“‘ How It Works

  1. πŸ†• Create a route in the UI β€” give it a name, add target URLs
  2. πŸ“‹ Copy the webhook URL β€” e.g. /api/hooks/a1b2c3d4e5f6g7h8
  3. πŸ”— Configure your Git host to send webhooks to that URL
  4. πŸ”€ Incoming webhooks are forwarded to all targets in parallel
  5. πŸ” Failed targets are retried up to 3 times with backoff

πŸ›‘οΈ Signature Verification

If a secret is configured on a route, incoming webhooks are verified:

  • GitHub β€” X-Hub-Signature-256 (HMAC-SHA256)
  • Gitea β€” X-Gitea-Signature (HMAC-SHA256)
  • GitLab β€” X-Gitlab-Token (plain token comparison)

πŸ₯ Health Check

curl http://localhost:6175/api/health
# β†’ {"status":"ok","version":"0.1.0","uptime":1234,"startedAt":"..."}

Used by the Docker Compose health check and compatible with any load balancer or monitoring system.

🎨 Theming

The app ships with stock Bootstrap and supports full theme replacement at runtime. Themes include Bootstrap itself β€” they're not layered on top β€” so every aspect of the UI can be customised.

How It Works

The endpoint /api/theme.css serves the active theme CSS:

  • Custom theme present (data/theme.css) β€” serves your theme
  • No custom theme β€” falls back to stock bootstrap.min.css

The app loads this single CSS endpoint and has no build-time Bootstrap dependency. Dark/light mode is supported via Bootstrap 5's data-bs-theme attribute, with a theme toggle in the navbar that persists the preference in a cookie.

Using a Theme

Drop a compiled CSS file into data/theme.css and reload. Remove the file to revert to stock Bootstrap.

cp themes/nbn24/dist/nbn24.css data/theme.css   # activate
rm data/theme.css                                 # revert

Included Theme: NBN24

The themes/nbn24/ directory contains an example theme based on the Bootswatch "Pulse" colour scheme β€” purple primary, no rounded corners, custom component styling. See themes/nbn24/README.md for build instructions.

Creating Your Own Theme

A theme is a standalone project that compiles a full Bootstrap 5 CSS bundle. Use themes/nbn24/ as a starting point:

cp -r themes/nbn24 themes/mytheme
cd themes/mytheme
  1. Edit scss/_variables.scss β€” override any Bootstrap SCSS variable
  2. Edit scss/_bootswatch.scss β€” add component-level style overrides (applied after Bootstrap)
  3. Rename the entry point if you like (scss/mytheme.scss) and update package.json scripts accordingly
  4. Build and deploy:
npm install && npm run build
cp dist/mytheme.css ../../data/theme.css

Themes are out-of-tree β€” they have their own package.json, node_modules, and build step. They don't depend on the webapp's build system and don't require Docker. Any tool that produces a CSS file (Sass, PostCSS, plain CSS, a Bootswatch download) will work, as long as it includes Bootstrap.

πŸ” Security

  • πŸ”‘ Passwords hashed with bcrypt (12 rounds) + optional pepper
  • πŸͺ HTTP-only session cookies (iron-session)
  • 🚫 IP-based rate limiting on login/register (10 attempts / 15 min)
  • βœ… Webhook signature verification (GitHub, Gitea, GitLab)
  • πŸ”’ All route management APIs require authentication
  • πŸ“‘ Webhook ingress endpoints are unauthenticated (as expected by Git platforms)

πŸ“ Project Structure

GitTaskFanOut/
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ data/                    # Config directory (gitignored)
β”‚   β”œβ”€β”€ routes.ini
β”‚   β”œβ”€β”€ users.ini
β”‚   β”œβ”€β”€ auth.ini
β”‚   └── theme.css            # Optional: custom theme (replaces Bootstrap)
β”œβ”€β”€ themes/                  # Out-of-tree theme projects
β”‚   └── nbn24/               # Example theme (Bootswatch Pulse)
β”‚       β”œβ”€β”€ package.json
β”‚       └── scss/
└── webapp/                  # Next.js app
    β”œβ”€β”€ Dockerfile
    β”œβ”€β”€ server.ts            # Custom server with morgan logging
    └── src/
        β”œβ”€β”€ components/      # ThemeDropdown (dark/light/auto toggle)
        β”œβ”€β”€ lib/             # Config, auth, relay, session, rate limiting
        β”œβ”€β”€ styles/          # App-specific CSS (no Bootstrap β€” served at runtime)
        └── pages/
            β”œβ”€β”€ _document.tsx # FOUC-free theme initialisation
            β”œβ”€β”€ index.tsx    # React-Bootstrap UI
            └── api/
                β”œβ”€β”€ health.ts
                β”œβ”€β”€ theme.css.ts  # Serves custom theme or stock Bootstrap
                β”œβ”€β”€ auth/    # login, logout, register, change-password, status
                β”œβ”€β”€ hooks/   # [...slug].ts β€” webhook receiver
                └── routes/  # CRUD + ping + duplicate

πŸ“œ License

LGPL-3.0 β€” see LICENSE

About

πŸ”€ Webhook fanout router for self-hosted Git platforms (Gitea, GitLab) with GitHub compatibility

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors