Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

GATETEST_HOOK.md

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

GATETEST_HOOK.mdBlame182 lines · 1 contributor
ad6d4adClaude1# GateTest ↔ GlueCron integration
2
3GlueCron exposes **two** inbound paths for GateTest to report scan results back.
4Use the primary path for normal traffic; the backup path exists so you always
5have a way in if the shared secret is misconfigured.
6
7Base URL: `https://<your-gluecron-host>` (e.g. `https://gluecron.com`)
8
9---
10
11## Primary: shared-secret hook
12
13**URL:** `POST /api/hooks/gatetest`
14
15### Auth (pick one)
16
17**Option A — Bearer token**
18```
19Authorization: Bearer <GATETEST_CALLBACK_SECRET>
20```
21or if the GateTest side can't set `Authorization`:
22```
23X-GateTest-Token: <GATETEST_CALLBACK_SECRET>
24```
25
26**Option B — HMAC-SHA256 over raw body**
27```
28X-GateTest-Signature: sha256=<hex(hmac_sha256(GATETEST_HMAC_SECRET, rawBody))>
29```
30
31Both are compared with a timing-safe equality check.
32
33### Request body (JSON)
34
35```json
36{
37 "repository": "owner/name",
38 "sha": "0123abcd0123abcd0123abcd0123abcd01234567",
39 "ref": "refs/heads/main",
40 "pullRequestNumber": 42,
41 "status": "passed",
42 "summary": "12 tests passed, 0 failed, 3.4s",
43 "details": { "...": "arbitrary JSON, persisted as-is" },
44 "durationMs": 3400
45}
46```
47
48| Field | Required | Notes |
49|---|---|---|
50| `repository` | ✅ | `"owner/name"` |
51| `sha` | ✅ | full 40-char commit SHA |
52| `status` | ✅ | `"passed"` \| `"failed"` \| `"error"` \| `"success"` |
53| `ref` | optional | defaults to `refs/heads/main` |
54| `pullRequestNumber` | optional | links the gate run to a PR |
55| `summary` | optional | shown on the gates UI |
56| `details` | optional | arbitrary JSON, stored verbatim |
57| `durationMs` | optional | for metrics |
58
59### Response
60
61```json
62{ "ok": true, "gateRunId": "uuid-of-the-inserted-row" }
63```
64
65On failure:
66- `400` — invalid JSON or missing required fields
67- `401` — missing / invalid credentials
68- `404` — repository not known to GlueCron
69- `500` — DB error (retry-safe, idempotent on sha + gate_name)
70
71### Side effects on a `failed` status
721. Row inserted in `gate_runs`
732. In-app notification to the repo owner (kind `gate_failed`)
743. Entry in `audit_log` (action `gate_callback`)
75
76---
77
78## Backup: personal access token
79
80**URL:** `POST /api/v1/gate-runs`
81
82### Auth
83Standard GlueCron PAT, created at `/settings/tokens`:
84```
85Authorization: Bearer glc_<64-hex-chars>
86```
87Alternative header if Bearer isn't possible:
88```
89X-API-Token: glc_<64-hex-chars>
90```
91
92### Request body
93Identical to the primary path, plus optional `gateName`:
94```json
95{
96 "repository": "owner/name",
97 "sha": "...",
98 "status": "passed",
99 "gateName": "GateTest",
100 "summary": "...",
101 "details": { }
102}
103```
104
105### Authorisation rules
106- The PAT's owner must match the repo's owner (MVP rule — will expand with orgs/teams in Block B).
107- Token is rejected if expired.
108- Successful use updates `api_tokens.last_used_at`.
109
110### Listing prior runs
111```
112GET /api/v1/gate-runs?repository=owner/name&limit=20
113Authorization: Bearer glc_...
114```
115
116Returns:
117```json
118{ "ok": true, "runs": [ {...}, ... ] }
119```
120
121---
122
123## Liveness probe (no auth)
124
125```
126GET /api/hooks/ping
127```
128Returns:
129```json
130{
131 "ok": true,
132 "service": "gluecron",
133 "hooks": ["gatetest", "gatetest/recent", "api/v1/gate-runs (backup)"],
134 "timestamp": "2026-04-14T..."
135}
136```
137
138Use this in GateTest's connectivity check before trying an authenticated call.
139
140---
141
142## Configuring the secrets
143
144On the GlueCron host (Railway / Fly / Docker) set either or both:
145```
146GATETEST_CALLBACK_SECRET=<long random bearer token>
147GATETEST_HMAC_SECRET=<long random HMAC key>
148```
149
150Generate with:
151```bash
152openssl rand -hex 32
153```
154
155Share the same value with GateTest. **If neither is set, the callback endpoint
156refuses all requests** — there is no anonymous write path by design.
157
158---
159
160## Example curl (primary path)
161
162```bash
163curl -X POST "https://gluecron.com/api/hooks/gatetest" \
164 -H "Authorization: Bearer $GATETEST_CALLBACK_SECRET" \
165 -H "Content-Type: application/json" \
166 -d '{
167 "repository": "alice/webapp",
168 "sha": "9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b",
169 "ref": "refs/heads/main",
170 "status": "failed",
171 "summary": "2 tests failed in src/auth.test.ts",
172 "durationMs": 4812
173 }'
174```
175
176Response:
177```json
178{ "ok": true, "gateRunId": "b7f3e2a1-..." }
179```
180
181The repo owner immediately sees a red notification; the run shows up at
182`/<owner>/<repo>/gates`.