neosourceDocs
Search docs

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`.

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

ownerrequired

Repository owner or organization slug.

string

reporequired

Repository name.

string

Responses

200The repository's GitHub relationship

application/json

GithubRelationshipResponse

object

A repository's GitHub relationship (ADR 0115 Phase 4a) — the response body of both `GET` and `POST /api/repos/{owner}/{repo}/github-relationship`. Every field comes from a column `GithubRepoSyncRecord` already selects (or, for `github_is_authority` and `upstream_url`, is derived from one), plus the one `github_meta_jobs` lookup the legacy status route already makes: no new store read, and no field that is structurally always `None`. `issues_done` / `issues_total` are carried deliberately even though they are backfill progress rather than relationship state. With them this response **strictly supersedes** [`GithubSyncStatusResponse`], which is the precondition for Phase 4c being a deletion of the legacy pair rather than a redesign of this one. Reserved to later phases and deliberately ABSENT — each would be a field that is always its default until the phase that fills it lands, and a client cannot tell "not shipped" from "nothing to report": `paused_refs` (8), the LFS digest / checked-at / scanner version (5 — `write_health` already carries that verdict), `native_actions_mode` (7), `cutover_state` (9), and the App's permissions and health, which `GET …/github-installation` already serves — one statement per fact.

authority_epochrequired

integerint64

Authority generation. The `expected_authority_epoch` a subsequent `POST` must echo back, and what invalidates a provider projection lease registered under an older one.

full_namerequired

string

GitHub `owner/name` at last observation.

github_is_authorityrequired

boolean

Whether `mode` is one of the GitHub-authoritative pair. Derived from `mode` and sent anyway, so the SPA never restates the rule — the two would then be two statements of one fact with nothing comparing them.

issues_donerequired

integerint32

Issues upserted by the latest backfill run; `0` when none has run.

issues_totalrequired

integerint32

Upper bound for the backfill progress bar; `0` when unknown.

last_error

string | null

Most recent sync/backfill error, if any.

last_synced_at

integer | nullint64

Millis since the Unix epoch of the last successful poll/page.

moderequired

GithubRelationshipMode

string

Which forge owns an imported repository's refs and provider-shaped data. The ONLY relationship vocabulary, in the database (`github_repo_sync.mode`), in Rust, on the wire and in the SPA. The legacy `synced` / `mirror_readonly` pair it replaced was collapsed onto [`Self::NeosourceReadonlyMirror`] by `migrations/20260902120000_github_relationship_contract.sql`.

"github_managed""neosource_readonly_mirror""neosource_managed""github_backup"

provider_admission_openrequired

boolean

Whether provider projections may be admitted at all. `false` is the default and the parked state.

sync_staterequired

GithubSyncState

string

Lifecycle of a repo's metadata sync (`github_repo_sync.state`).

"backfilling""live""error"

upstream_urlrequired

string

The repository's page on github.com, so the SPA can link out without hard-coding the provider's host.

write_healthrequired

GithubWriteHealth

string

Whether a GitHub-authoritative repository is currently safe to write through — the `github_repo_sync.write_health` column. Closed vocabulary; the tokens are the CHECK list at `migrations/20260901120000_github_relationship_expand.sql`. The default for a fresh relationship is [`Self::LfsUnverified`], not `Healthy`: a repo whose LFS posture nobody has looked at yet is not known-good, and the fail-closed direction is the one that does not push objects at an upstream that will reject or mangle them.

"healthy""lfs_unverified""lfs_blocked""paused""error"

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