Skip to content

Commit dea4118

Browse files
yordiszbruhnkethatdaveb
authored
feat(trogon-source-gitlab): scaffold GitLab webhook source (#99)
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: Zach Bruhnke <zach@ordinary.company> Co-authored-by: Dave <dave@bruhnke.us>
1 parent 1c17914 commit dea4118

14 files changed

Lines changed: 1487 additions & 0 deletions

File tree

devops/docker/compose/.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@
1010
# GITHUB_NATS_ACK_TIMEOUT_SECS=10
1111
# GITHUB_MAX_BODY_SIZE=26214400
1212

13+
# --- GitLab Source ---
14+
# GITLAB_WEBHOOK_SECRET=
15+
# GITLAB_WEBHOOK_PORT=8080
16+
# GITLAB_SUBJECT_PREFIX=gitlab
17+
# GITLAB_STREAM_NAME=GITLAB
18+
# GITLAB_STREAM_MAX_AGE_SECS=604800
19+
# GITLAB_NATS_ACK_TIMEOUT_MS=10000
20+
# GITLAB_MAX_BODY_SIZE=26214400
21+
1322
# --- Linear Source ---
1423
# LINEAR_WEBHOOK_SECRET=
1524
# LINEAR_WEBHOOK_PORT=8080

devops/docker/compose/compose.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,31 @@ services:
6767
start_period: 10s
6868
retries: 3
6969

70+
trogon-source-gitlab:
71+
build:
72+
context: ../../../rsworkspace
73+
dockerfile: ../devops/docker/compose/services/trogon-source-gitlab/Dockerfile
74+
environment:
75+
NATS_URL: "nats:4222"
76+
GITLAB_WEBHOOK_SECRET: "${GITLAB_WEBHOOK_SECRET:-}"
77+
GITLAB_WEBHOOK_PORT: "${GITLAB_WEBHOOK_PORT:-8080}"
78+
GITLAB_SUBJECT_PREFIX: "${GITLAB_SUBJECT_PREFIX:-gitlab}"
79+
GITLAB_STREAM_NAME: "${GITLAB_STREAM_NAME:-GITLAB}"
80+
GITLAB_STREAM_MAX_AGE_SECS: "${GITLAB_STREAM_MAX_AGE_SECS:-604800}"
81+
GITLAB_NATS_ACK_TIMEOUT_MS: "${GITLAB_NATS_ACK_TIMEOUT_MS:-10000}"
82+
GITLAB_MAX_BODY_SIZE: "${GITLAB_MAX_BODY_SIZE:-26214400}"
83+
RUST_LOG: "${RUST_LOG:-info}"
84+
depends_on:
85+
nats:
86+
condition: service_healthy
87+
restart: unless-stopped
88+
healthcheck:
89+
test: ["CMD", "curl", "-sf", "http://localhost:${GITLAB_WEBHOOK_PORT:-8080}/health"]
90+
interval: 10s
91+
timeout: 3s
92+
start_period: 10s
93+
retries: 3
94+
7095
trogon-source-slack:
7196
build:
7297
context: ../../../rsworkspace
@@ -98,6 +123,7 @@ services:
98123
environment:
99124
NGROK_AUTHTOKEN: "${NGROK_AUTHTOKEN:-}"
100125
GITHUB_ADDR: "trogon-source-github:${GITHUB_WEBHOOK_PORT:-8080}"
126+
GITLAB_ADDR: "trogon-source-gitlab:${GITLAB_WEBHOOK_PORT:-8080}"
101127
LINEAR_ADDR: "trogon-source-linear:${LINEAR_WEBHOOK_PORT:-8080}"
102128
SLACK_ADDR: "trogon-source-slack:${SLACK_WEBHOOK_PORT:-3000}"
103129
entrypoint:
@@ -110,6 +136,9 @@ services:
110136
github:
111137
addr: $${GITHUB_ADDR}
112138
proto: http
139+
gitlab:
140+
addr: $${GITLAB_ADDR}
141+
proto: http
113142
linear:
114143
addr: $${LINEAR_ADDR}
115144
proto: http
@@ -121,6 +150,8 @@ services:
121150
depends_on:
122151
trogon-source-github:
123152
condition: service_healthy
153+
trogon-source-gitlab:
154+
condition: service_healthy
124155
trogon-source-linear:
125156
condition: service_healthy
126157
trogon-source-slack:
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# ── Stage 1: chef — generate dependency recipe ──────────────────────────────
2+
FROM rust:1.93-slim AS chef
3+
4+
RUN cargo install cargo-chef --locked
5+
6+
WORKDIR /build
7+
8+
# ── Stage 2: planner — capture dependency graph ─────────────────────────────
9+
FROM chef AS planner
10+
11+
COPY Cargo.toml Cargo.lock ./
12+
COPY crates/ crates/
13+
14+
RUN cargo chef prepare --recipe-path recipe.json
15+
16+
# ── Stage 3: builder — cached dependency build + final compile ──────────────
17+
FROM chef AS builder
18+
19+
COPY --from=planner /build/recipe.json recipe.json
20+
RUN cargo chef cook --release --recipe-path recipe.json -p trogon-source-gitlab
21+
22+
COPY Cargo.toml Cargo.lock ./
23+
COPY crates/ crates/
24+
25+
RUN cargo build --release -p trogon-source-gitlab && \
26+
strip target/release/trogon-source-gitlab
27+
28+
# ── Stage 4: runtime ────────────────────────────────────────────────────────
29+
FROM debian:bookworm-20250317-slim AS runtime
30+
31+
RUN apt-get update && apt-get install -y --no-install-recommends \
32+
ca-certificates curl \
33+
&& rm -rf /var/lib/apt/lists/*
34+
35+
RUN useradd --no-create-home --shell /usr/sbin/nologin trogon
36+
37+
COPY --from=builder /build/target/release/trogon-source-gitlab /usr/local/bin/trogon-source-gitlab
38+
39+
USER trogon
40+
41+
EXPOSE 8080
42+
43+
STOPSIGNAL SIGTERM
44+
45+
ENTRYPOINT ["/usr/local/bin/trogon-source-gitlab"]
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Receiving GitLab Webhooks Locally
2+
3+
## Prerequisites
4+
5+
- Docker Compose
6+
- A [GitLab](https://gitlab.com) project with maintainer access (or a self-hosted instance)
7+
- An [ngrok](https://ngrok.com) account (free tier works)
8+
9+
## 1. Get your ngrok tunnel URL
10+
11+
Start only ngrok and NATS to obtain a public URL before configuring GitLab:
12+
13+
```bash
14+
docker compose --profile dev up ngrok nats
15+
```
16+
17+
Find the tunnel URL in the ngrok container logs:
18+
19+
```bash
20+
docker compose logs ngrok
21+
```
22+
23+
Look for the `gitlab` tunnel URL (e.g. `https://abc123.ngrok-free.app`).
24+
25+
## 2. Configure your GitLab webhook
26+
27+
1. Go to **Settings → Webhooks** in your GitLab project
28+
2. Click **Add new webhook**
29+
3. Set:
30+
- **URL**: `https://<ngrok-url>/webhook`
31+
- **Secret token**: a secret of your choice (you will use this as `GITLAB_WEBHOOK_SECRET`)
32+
4. Select the trigger events you want to receive (e.g. Push events, Merge request events)
33+
5. Click **Add webhook**
34+
35+
## 3. Start the webhook receiver
36+
37+
Set `GITLAB_WEBHOOK_SECRET` in your `.env` to the secret token from step 2,
38+
then bring up the full stack:
39+
40+
```bash
41+
docker compose --profile dev up
42+
```
43+
44+
## 4. Verify
45+
46+
Trigger an event in GitLab (e.g. push a commit or open a merge request). You should see:
47+
48+
- The webhook receiver log the incoming event
49+
- The event published to NATS on `gitlab.{event}`
50+
51+
You can inspect NATS with:
52+
53+
```bash
54+
nats sub -s nats://nats.trogonai.orb.local:4222 "gitlab.>"
55+
```
56+
57+
Without `--profile dev`, ngrok is excluded and only the core services start.
58+
59+
## Environment variables
60+
61+
| Variable | Required | Default | Description |
62+
|---|---|---|---|
63+
| `GITLAB_WEBHOOK_SECRET` | yes || Secret token configured in GitLab's webhook settings |
64+
| `NGROK_AUTHTOKEN` | yes (dev profile) || ngrok auth token |
65+
| `GITLAB_WEBHOOK_PORT` | no | `8080` | HTTP port for the webhook receiver |
66+
| `GITLAB_SUBJECT_PREFIX` | no | `gitlab` | NATS subject prefix (must be valid NATS token) |
67+
| `GITLAB_STREAM_NAME` | no | `GITLAB` | JetStream stream name (must be valid NATS token) |
68+
| `GITLAB_STREAM_MAX_AGE_SECS` | no | `604800` | Max message age in seconds (7 days) |
69+
| `GITLAB_NATS_ACK_TIMEOUT_MS` | no | `10000` | JetStream ACK timeout in milliseconds |
70+
| `GITLAB_MAX_BODY_SIZE` | no | `26214400` | Maximum webhook body size in bytes (25 MB) |
71+
| `NATS_URL` | no | `localhost:4222` | NATS server URL(s) |
72+
| `RUST_LOG` | no | `info` | Log level |

rsworkspace/Cargo.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rsworkspace/crates/acp-telemetry/src/service_name.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub enum ServiceName {
66
AcpNatsStdio,
77
AcpNatsWs,
88
TrogonSourceGithub,
9+
TrogonSourceGitlab,
910
TrogonSourceLinear,
1011
TrogonSourceSlack,
1112
}
@@ -16,6 +17,7 @@ impl ServiceName {
1617
Self::AcpNatsStdio => "acp-nats-stdio",
1718
Self::AcpNatsWs => "acp-nats-ws",
1819
Self::TrogonSourceGithub => "trogon-source-github",
20+
Self::TrogonSourceGitlab => "trogon-source-gitlab",
1921
Self::TrogonSourceLinear => "trogon-source-linear",
2022
Self::TrogonSourceSlack => "trogon-source-slack",
2123
}
@@ -40,6 +42,10 @@ mod tests {
4042
ServiceName::TrogonSourceGithub.as_str(),
4143
"trogon-source-github"
4244
);
45+
assert_eq!(
46+
ServiceName::TrogonSourceGitlab.as_str(),
47+
"trogon-source-gitlab"
48+
);
4349
assert_eq!(
4450
ServiceName::TrogonSourceLinear.as_str(),
4551
"trogon-source-linear"
@@ -58,6 +64,10 @@ mod tests {
5864
format!("{}", ServiceName::TrogonSourceGithub),
5965
"trogon-source-github"
6066
);
67+
assert_eq!(
68+
format!("{}", ServiceName::TrogonSourceGitlab),
69+
"trogon-source-gitlab"
70+
);
6171
assert_eq!(
6272
format!("{}", ServiceName::TrogonSourceLinear),
6373
"trogon-source-linear"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "trogon-source-gitlab"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[lints]
7+
workspace = true
8+
9+
[[bin]]
10+
name = "trogon-source-gitlab"
11+
path = "src/main.rs"
12+
13+
[dependencies]
14+
acp-telemetry = { workspace = true }
15+
async-nats = { workspace = true, features = ["jetstream"] }
16+
axum = { workspace = true }
17+
bytes = { workspace = true }
18+
bytesize = "2.3.1"
19+
sha2 = "0.10"
20+
subtle = "2.6"
21+
tokio = { workspace = true, features = ["full"] }
22+
tower-http = { workspace = true, features = ["limit"] }
23+
tracing = { workspace = true }
24+
trogon-nats = { workspace = true }
25+
trogon-std = { workspace = true }
26+
27+
[dev-dependencies]
28+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
29+
tower = "0.5"
30+
tracing-subscriber = { workspace = true }
31+
trogon-nats = { workspace = true, features = ["test-support"] }
32+
trogon-std = { workspace = true, features = ["test-support"] }

0 commit comments

Comments
 (0)