CI/CD runner protocol — implementation
git-shark does not ship its own runner. It implements the server side of the Forgejo/Gitea
runner.v1 protocol so stock forgejo-runner / act_runner binaries work unchanged. This document
covers how the server side is built and what is / isn't done.
Component map
| Component | File | Role |
|---|---|---|
| Proto definitions | src/main/proto/{ping,runner}/v1/*.proto | MIT-licensed copies of gitea.com/gitea/actions-proto-def, with java_package/java_multiple_files options added. |
| Generated messages | de.workaround.ci.proto.* (build output) | Protobuf message classes generated by protobuf-maven-plugin at generate-sources. |
| Connect endpoint | ci/ConnectRunnerResource.java | JAX-RS resource serving the Connect unary RPCs under /api/actions. |
| Registration/presence | ci/RunnerRegistrationService.java | Token issue, runner register/declare/authenticate, list/delete. |
| Entities | model/CiRunner.java, model/CiRunnerRegistrationToken.java | Persisted state (migration V19). |
| Admin UI | ci/AdminRunnerResource.java + templates/AdminRunnerResource/ | Token generation, runner list, deletion. |
| Admin gate | account/AdminAccess.java | Config-driven instance-admin check. |
Key decisions (and why)
- Reuse the Forgejo/Gitea runner, don't write our own. The wire protocol is small, open, and MIT-licensed; the runner ecosystem and GHA-compatible workflow format come for free. The real cost is server-side workflow semantics (trigger/DAG/matrix), not the transport — see the issue for the full rationale.
- Connect unary over plain JAX-RS, not
quarkus-grpc. Connect unary RPC is just an HTTPPOSTwith a serialized-protobuf body and a serialized-protobuf200body. We only need the generated message classes; serving them from ordinary JAX-RS resources avoids pulling in a gRPC server (extra listener, HTTP/2) we don't use. Henceprotobuf-maven-plugin(messages only) rather than the gRPC codegen. Errors use the Connect JSON error shape ({"code","message"}) with the matching HTTP status. - Two secret types, hashed at rest. A reusable, instance-scoped registration token (admin
issues it; runner presents it once in the
Registerbody) and a permanent per-runner secret (minted inRegister, sent to the runner exactly once, presented inx-runner-tokenthereafter). Only SHA-256 hashes are stored — same model asAccessToken. - Instance-scope, config-based admin. No admin role in the schema yet;
AdminAccessreadsgitshark.admin.handles. Deliberately minimal so phase 1 doesn't drag a roles migration with it. uuiddistinct from the DB primary key. The runner echoesuuidin headers; keeping it separate from the internalUUID idmeans the runner never learns our primary key.
What works today
protobuf-maven-plugingenerates theping.v1+runner.v1message classes at build time.Pinghealth check.Register: validates the registration token, creates aci_runner, returns the per-runner secret once. Registration tokens are reusable.Declare: authenticates byuuid+ secret, refreshes version/labels/last_seen, returns the runner.- Admin UI: generate/delete registration tokens, list/delete runners; gated by
AdminAccessand the/admin/*authenticated policy. - Tests:
RunnerRegistrationServiceTest(service),ConnectRunnerResourceTest(protobuf-over-HTTP round-trip for Ping/Register/Declare + auth failures),AdminAccessTest(admin gate).
What still needs to be implemented
- Run loop:
FetchTask(long-poll withtasks_version),UpdateTask,UpdateLog(offset /ack_indexresume). Not served yet. - Tables:
action_run,action_task,action_log(or log-blob storage). - Workflow pipeline: parse
.forgejo/workflows/*.ymlat the pushed head, evaluateon:triggers (push only for the MVP), expand a single job into a Task payload. Noneeds/matrixyet. - Run UI: per-repository run list + run detail with live per-step status and logs.
- Task state machine: timeout / zombie handling when a runner vanishes mid-task.
- Real-runner integration test: protocol round-trip against an actual
forgejo-runnercontainer (the current endpoint test uses a hand-built protobuf client, not the binary). - Later phases: secrets/variables delivery, label-based matching, concurrency/cancellation,
artifacts (
ACTIONS_RESULTS_URL), repo/org-scoped and ephemeral runners, commit/MR status.
References
- Protos: https://gitea.com/gitea/actions-proto-def (MIT)
- Gitea Actions design (server/runner split): https://docs.gitea.com/usage/actions/design
- Forgejo ↔ Gitea shared-protocol confirmation: https://code.forgejo.org/forgejo/runner/issues/525