Get a repository's GitHub relationship
GET/api/repos/{owner}/{repo}/github-relationship
getGithubRelationship
Which forge owns this repository's refs and provider-shaped data, the upstream it is tied to, its authority generation, and the health/admission posture of the direct-write path — plus the latest metadata backfill's issue counters. `404` only when the repository has **no** relationship row at all. A row this deployment is authoritative for (`neosource_managed`, `github_backup`) is reported here, deliberately: it is the relationship's history, and it is what explains why a once-imported repository cannot be re-linked to GitHub. The older `GET …/github-sync` answers a narrower question — "is there a running metadata sync?" — and 404s those rows. `authority_epoch` is the value a subsequent `POST` must echo back as `expected_authority_epoch`. `metadata_mode` says whether GitHub's issues are pulled (`off` = an attached repository that keeps its own), `authority_handoff` how a `neosource_managed` row left GitHub (`detached` or `cut_over`). `blockers` lists everything that currently stops GitHub sync, each with a stable `fix` code and, where the fix is made elsewhere, a `fix_url`; `attach` is the attach in flight, else the latest one.
Authentication optional — this operation also accepts anonymous requests. When authenticating, use a bearer token or a session cookie.
curl
curl -X GET 'https://neosource.dev/api/repos/OWNER/REPO/github-relationship' \
-H 'Authorization: Bearer $NEOSOURCE_TOKEN'fetch
fetch("https://neosource.dev/api/repos/OWNER/REPO/github-relationship", {
method: "GET",
headers: {
Authorization: "Bearer $NEOSOURCE_TOKEN",
},
});Path parameters
ownerrequiredRepository owner or organization slug.
reporequiredRepository name.
Responses
200The repository's GitHub relationship
application/json
Standard errors
Bodies documented once for the whole API — see standard errors.
- 400Bad Request — one of: invalid_input
- 403Forbidden — one of: forbidden
- 404Not Found — one of: not_found
- 423Locked — one of: busy
- 429Rate limited — retry after the `Retry-After` header
- 500Internal server error
- 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
- 504Gateway timeout — the request exceeded the server's handling budget
Schemas
Referenced above. Listed here rather than expanded inline, so the same definition is not repeated at every level.
GithubAttachOrigin
Who started an attach — `github_attach_runs.origin`.
"import""user"
GithubAttachRunState
Lifecycle of one attach attempt — `github_attach_runs.state`. ```text planning ─► planned ─(confirm)─► frozen ─► publishing ─► applying ─► applied ▲ │ │ │ └── needs_reconfirm ◄──(undo)───┴───────────┘ (+ failed, cancelled, expired) ``` The six nonterminal states are exactly the partial unique index `github_attach_runs_one_nonterminal_per_repo`, so a repository has at most one attach in flight.
"planning""planned""frozen""publishing""applying""applied""needs_reconfirm""failed""cancelled""expired"
GithubSyncBlocker
Everything that stops GitHub sync, enabling or ongoing: closed and typed, so the GitHub panel can name a fix for each. Each variant mirrors an existing core outcome rather than restating it: the binding ones are [`GithubAppBindingHealth`] values, `RulesetAudit` / `ProtectionEventsNotSubscribed` / `AdministrationReadMissing` are [`RulesetAuditOutcome`] refusals, `WritesRefused` is [`GithubWriteHealth::refuses_managed_writes`], the LFS ones are [`LfsVerificationResult`] verdicts. An empty or unrelated upstream is not a blocker (D11), nor is a tombstone (D7). Serialized internally tagged by `kind`, which is also [`Self::kind`].
The GitHub-sync offering is not enabled for this repository.
kindrequired"feature_not_offered"
No App installation is bound to the repository.
kindrequired"no_app_binding"
[`GithubAppBindingHealth::Unverified`], or `RulesetUnverified` with no refusing audit outcome recorded (awaiting a (re-)audit).
kindrequired"binding_unverified"
[`GithubAppBindingHealth::Error`]: the binding probe failed.
kindrequired"binding_error"
[`GithubAppBindingHealth::Revoked`].
kindrequired"binding_revoked"
[`GithubAppBindingHealth::InsufficientScope`].
kindrequired"binding_insufficient_scope"
The ruleset audit refused the binding for `outcome` ([`RulesetAuditOutcome::remedy`] is the fix). A struct variant because an internally tagged enum cannot carry a bare string newtype.
kindrequired"ruleset_audit"outcomerequired
[`RulesetAuditOutcome::ProtectionEventsNotSubscribed`], with the webhook events the installation has not accepted (from the audit's detail; display only).
kindrequired"protection_events_not_subscribed"missing_eventsrequired- items
[`RulesetAuditOutcome::ClassicProtectionUnreadable`] on an installation without `administration: read`.
kindrequired"administration_read_missing"
The write health refuses managed writes on its own ([`GithubWriteHealth::refuses_managed_writes`]).
healthrequiredkindrequired"writes_refused"
[`LfsVerificationResult::PointersDetected`] over the post-attach ref set, published refs included.
kindrequired"lfs_pointers_detected"
[`LfsVerificationResult::Unverified`], or no verification at all.
kindrequired"lfs_unverified"
The GitHub repository is archived.
kindrequired"github_archived"
GitHub advertises `refname` inside the preserved namespace.
kindrequired"github_advertises_preserved_prefix"refnamerequired
This repository already holds `refname` inside the preserved namespace.
kindrequired"local_ref_under_preserved_prefix"refnamerequired
No preserved name within [`MAX_REFNAME_BYTES`] can be formed for `refname`.
kindrequired"preserved_name_too_long"refnamerequired
A GitHub ref intent is not terminal (an `ambiguous` one included).
kindrequired"unsettled_ref_intent"
Another attach run for this repository is not settled.
kindrequired"unsettled_attach"
GithubSyncFix
The stable code the GitHub panel renders as the remedy for a [`GithubSyncBlocker`]. Closed, so the SPA's copy table is exhaustive; one code may answer several blockers ([`GithubSyncBlocker::fix`] is the map).
"contact_operator""install_github_app""wait_for_binding_audit""recheck_github_app""reinstall_github_app""grant_github_app_permissions""fix_github_rulesets""accept_github_app_events""resume_sync""check_write_health""remove_lfs_pointers""recheck_lfs""unarchive_github_repository""remove_preserved_refs_on_github""rename_local_ref""resolve_ref_intent""settle_attach"