Shared Forgejo API contract: pinned spec + operational policy for Fjord and fj
  • Shell 78.4%
  • Makefile 21.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Stephen Way 36040321e3
All checks were successful
CI / Contract drift (push) Successful in 6s
Re-vendor the contract at Forgejo 16.0.3 (#5)
rasterhub.com now runs `16.0.3+gitea-1.22.0`; the vendored spec was pinned at `15.0.2`. This is `make fetch` + `make regenerate` against the live swagger, nothing hand-written.

Twelve paths are new, no path or schema was removed, and no schema gained a required field. The six that matter to a client are the Actions endpoints Forgejo 15 has no answer for:

```
GET  /repos/{owner}/{repo}/actions/runs/{run_id}/jobs
GET  /repos/{owner}/{repo}/actions/jobs/{job_id}/logs
GET  /repos/{owner}/{repo}/actions/runs/{run_id}/logs
POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel
GET  /repos/{owner}/{repo}/actions/artifacts (+ /{artifact_id}, /{artifact_id}/zip)
GET  /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts
```

The rest are admin token management, an ActivityPub remote-follow, and a global run list. Two new schemas: `ActionArtifact` and `APRemoteFollowOption`.

Per OPERATIONS.md this is the low-risk shape of a re-vendor: new endpoints reach neither consumer until its generator filter opts in, so nothing here changes generated code on its own.

`versionFloor` stays at `7.0.0`. 16.0.3 is a capability ceiling to detect at runtime, not a new floor, because both the LTS (15) and stable (16) lines stay supported.

### The one field that goes the other way

`EditPullRequestOption.draft` disappears. It was added to the vendored spec by hand in #3, and a faithful re-fetch drops it.

This is not an upstream regression. Forgejo carries no `Draft` field on `EditPullRequestOption` in either `v15.0.2` or `v16.0.3`, and `EditPullRequest` in `routers/api/v1/repo/pull.go` reads no such field in either tag. The property described a request field the server has never parsed, so restoring it would re-vendor a fiction. The `patches/` overlay step that would have made the hand-edit durable across a re-fetch was never wired into the Makefile, which is why #3 vanished silently here rather than conflicting.

Both consumers send `draft: false` to mark a pull request ready (`fj pr ready`, Fjord's `PullRequestDetailView.markReady`). That path is tracked separately. It does not block this re-vendor: neither consumer's generated code moves until it bumps this submodule pointer.

This pull request is deliberately open as a draft, as the live-server test for exactly that question.

Reviewed-on: #5
2026-09-11 04:16:33 +00:00
.forgejo/workflows Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
patches Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
scripts Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
.gitattributes Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
.gitignore Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
CODEOWNERS Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
GAPS.md Document live-verified API gaps from the flux F8 soak (#2) 2026-06-10 04:23:46 +00:00
LICENSE Add Apache 2.0 licence and NOTICE (#4) 2026-08-04 16:55:02 +00:00
Makefile Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
NOTICE Add Apache 2.0 licence and NOTICE (#4) 2026-08-04 16:55:02 +00:00
openapi.v1.yaml Re-vendor the contract at Forgejo 16.0.3 (#5) 2026-09-11 04:16:33 +00:00
openapi.yaml Re-vendor the contract at Forgejo 16.0.3 (#5) 2026-09-11 04:16:33 +00:00
OPERATIONS.md Extract the Forgejo API contract into a standalone repo 2026-05-20 19:33:50 -07:00
policy.yaml Mark Comment.id required (#1) 2026-05-21 05:25:25 +00:00
README.md Document live-verified API gaps from the flux F8 soak (#2) 2026-06-10 04:23:46 +00:00
swagger.v1.json Re-vendor the contract at Forgejo 16.0.3 (#5) 2026-09-11 04:16:33 +00:00

forgejo-api-contract

The shared API contract for Forgejo clients built at Raster & State. One pinned spec, one operational policy, consumed by both Fjord (Swift / iOS) and fj (Rust CLI).

This repo is the single source of truth for:

  • which Forgejo API version the clients target,
  • the OpenAPI 3.0 document they generate code from,
  • the operational policy (retry budget, body cap, redaction list, version floor) the clients are expected to honor in lockstep.

It contains no compiled code. Each consumer vendors this repo as a git submodule and runs its own language-specific code generation.

What's here

Path Role
swagger.v1.json Upstream Forgejo spec, vendored at a pinned version (Forgejo 15.0.2, Gitea 1.22-compatible).
openapi.v1.yaml Raw OpenAPI 3.0 conversion of the swagger via swagger2openapi. Committed so consumers don't need Node to build.
openapi.yaml The patched spec: openapi.v1.yaml plus policy.yaml's requiredOverrides: applied. This is the document consumers generate from.
policy.yaml Operational policy shared by every consumer: version floor, retry table, body cap, redaction allowlist, optionality overrides, required-field overrides.
patches/ Reserved for future Redocly-style overlays. Empty today; the simple required: rewrites are driven from policy.yaml.
scripts/apply-required-overrides.sh Reads policy.yaml's requiredOverrides:, applies them to openapi.v1.yaml, writes openapi.yaml. Validates each schema and field exists before writing.
scripts/generate-policy-swift.sh Consumer-side convenience: renders policy.yaml into a Swift constants file. Invoked by Fjord with its own output path. A generate-policy-rs.sh will join it when fj adopts the contract.
Makefile Contract-level targets: fetch, convert, patch, check.
OPERATIONS.md Re-vendor cadence, patch hygiene, ownership, breaking-change protocol.
GAPS.md Live-verified divergences between the vendored spec and real deployed servers (version skew, undocumented semantics, missing webhook surfaces).

Contract-level commands

make help          # list targets
make fetch         # re-download swagger.v1.json from rasterhub.com
make convert       # rerun swagger2openapi (writes openapi.v1.yaml)
make patch         # apply policy.yaml requiredOverrides (writes openapi.yaml)
make regenerate    # convert + patch
make check         # fail if either committed spec drifts (CI gate)

make check is this repo's CI gate. Language-specific code generation (Swift types, Rust constants) is each consumer's responsibility and runs in the consumer's own CI.

How consumers use this

Each consumer adds this repo as a git submodule, points its code generator at openapi.yaml, and runs its own policy.yaml-to-constants step:

  • Fjord vendors the submodule at Fjord/Tools/forgejo-contract/, runs swift-openapi-generator against openapi.yaml, and runs scripts/generate-policy-swift.sh to produce ForgejoPolicy constants.
  • fj (planned) will vendor the submodule, generate Rust models, and run a generate-policy-rs.sh for the matching policy.rs constants.

Prerequisites

  • node 24.x (for swagger2openapi, invoked via npx --yes).
  • yq, Mike Farah's Go implementation (not the Python yq wrapper). The patching script refuses to run on the wrong flavor.
  • make, bash, curl.

Re-vendoring

See OPERATIONS.md for the cadence, the patch-hygiene rules, and the major-version bump protocol.

versionFloor vs spec version

policy.yaml's versionFloor.semver is the minimum Forgejo major version clients agree to talk to (7.0.0, set by fj's pre-existing version-warning baseline). It is independent of the spec version vendored in swagger.v1.json (Forgejo 15.0.2 today); the spec floats forward, the floor changes only when both clients agree to drop compatibility with older servers.