Federated via graft
2.7 kB
72 lines
1# graft
2
3A daemon that mirrors repositories between Forgejo and Radicle: git content, issues, and pull requests / patches.
4
5It runs on a timer, keeps state in a local SQLite file, and never force-pushes. Real divergences between the two sides are reported and left for humans to resolve.
6
7## What it syncs
8
9- **Git content**: the default branch, fast-forward only.
10- **Issues**: Forgejo issues become Radicle issues and vice versa. Create-only for now — edits made after the first mirror aren't propagated yet.
11- **Patches / pull requests**: a Forgejo PR opens a Radicle patch (and back), by pushing the PR's head commit to `refs/patches` on the Radicle side, or as a branch + PR on the Forgejo side.
12
13## Planned: Forgejo-to-Forgejo via Authorized Integrations
14
15Right now, two Forgejo instances stay in sync by both pairing with the same Radicle repository — Radicle is the hub. An alternative worth supporting directly: one instance's CI authenticates straight to another's API using [Forgejo's Authorized Integrations](https://forgejo.org) (a short-lived OIDC token, no stored secret), instead of routing through Radicle at all. Not implemented yet — noted here so the config shape leaves room for it.
16
17## Why
18
19Forgejo and Radicle solve the same problem — hosting and reviewing changes to a git repository — with opposite architectures: one is a server you point a browser at, the other is a peer-to-peer protocol with no server at all. `graft` lets a project exist on both.
20
21## Requirements
22
23- Go 1.23+ to build
24- `git`
25- the `rad` CLI, with `git-remote-rad` on `PATH`, and a Radicle node already running with its own identity (`rad auth`)
26- a Forgejo access token scoped to `write:repository` and `write:issue` on the repo you're syncing
27
28## Build
29
30```sh
31go build -o graft ./cmd/sync
32```
33
34## Config
35
36```yaml
37sync_interval: 5m
38state_db: /var/lib/graft/state.db
39
40repos:
41 - name: my-project
42 forgejo:
43 base_url: https://git.example.org
44 owner: alice
45 repo: my-project
46 token_file: /etc/graft/my-project.token
47 radicle:
48 rid: rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
49 http_base_url: https://seed.example.org
50 rad_home: /home/graft/.radicle
51 sync:
52 git: true
53 issues: true
54 patches: true
55```
56
57Tokens live in their own files, never inline in the config. `graft` reads them at startup and expects `chmod 600`.
58
59## Run
60
61```sh
62graft -config /etc/graft/config.yaml # loop forever, per sync_interval
63graft -config /etc/graft/config.yaml -once # one pass, then exit
64```
65
66A systemd unit is in `systemd/graft.service`.
67
68Full walkthrough, from a blank server to a running mirror: [TUTORIAL.md](TUTORIAL.md).
69
70## License
71
72GPLv3. See [LICENSE](LICENSE).