Confirm a GitHub attach plan
POST/api/repos/{owner}/{repo}/github-attach/confirm
confirmGithubAttach
Confirms the plan the caller reviewed, for the attach worker to carry out; the request never waits on GitHub. Refused with `409 relationship_conflict` unless the run is this repository's and `planned`, `plan_hash` is the plan's and the plan has not expired, and the relationship is still at `expected_authority_epoch` (`null` = no relationship) — re-read the preview and confirm again. When the preview lists `publishes`, `confirm_publish` must be `true` (those refs are pushed to GitHub under their own names), else `409 attach_publish_unconfirmed` and nothing is recorded; on a plan that publishes nothing it is ignored. Requires repository **admin** from a **signed-in session** or an access token with no workspace or repository lock (ADR 0162); a locked token is refused with `403 forbidden`.
Requires authentication using a bearer token or a session cookie — see tokens and scopes.
curl
curl -X POST 'https://neosource.dev/api/repos/OWNER/REPO/github-attach/confirm' \
-H 'Authorization: Bearer $NEOSOURCE_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"run_id":"string","plan_hash":"string","expected_authority_epoch":"string","confirm_publish":false}'fetch
fetch("https://neosource.dev/api/repos/OWNER/REPO/github-attach/confirm", {
method: "POST",
headers: {
Authorization: "Bearer $NEOSOURCE_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({"run_id":"string","plan_hash":"string","expected_authority_epoch":"string","confirm_publish":false}),
});Path parameters
ownerrequiredRepository owner or organization slug.
reporequiredRepository name.
Request bodyrequired
application/json
Responses
202Confirmed; the attach proceeds in the background
application/json
Standard errors
Bodies documented once for the whole API — see standard errors.
- 400Bad Request — one of: invalid_input
- 401Authentication required
- 403Forbidden — one of: forbidden
- 404Not Found — one of: not_found
- 409Conflict — one of: attach_publish_unconfirmed, conflict, relationship_conflict, relationship_unavailable
- 429Rate limited — retry after the `Retry-After` header
- 500Internal server error
- 502Bad Gateway — one of: upstream
- 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.
AttachPrChange
What an attach does to an open pull request's refs.
"head_follows""head_preserved""base_moves"
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"
AttachPublishKind
What a publish sends to GitHub: a branch or a tag, read off the refname.
"branch""tag"
AttachRefClass
How one ref's local and GitHub tips compare — the left column of D4.
"equal""local_behind""local_ahead""diverged""only_github""only_neosource"
AttachRefOutcome
What the attach does with one ref — the middle column of D4.
"keep""fast_forward""create""preserve_and_reset""preserve""drop""publish"