Skip to content

feat(agent-actions): cancel in-flight CI runs when a PR is auto-closed for the contributor cap #2462

Description

@JSONbored

Parent: #1936
Related: #2270 (this triggers off the contributor_cap close that issue introduces)

Motivation

#2270 adds a per-contributor open-PR/issue cap with auto-close over the limit. Closing a PR for
being over the cap should also stop burning CI minutes on that PR's in-flight Actions runs — today
nothing in this codebase cancels a GitHub Actions run: there is no call to
POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel (or any equivalent) anywhere in src/.

Important constraint found while scoping this: the GitHub App's default_permissions
(src/selfhost/setup-wizard.ts) currently requests pull_requests, contents, issues, checks,
metadatanot actions. Listing/cancelling workflow runs via the Actions REST API needs
actions: write (and effectively actions: read to list runs for a head SHA first). Adding this
scope means every already-installed self-hosted operator will see a "this app wants additional
permissions" prompt and must re-approve before cancellation works for them — this is a permission
rollout, not just a code change, and installs that haven't re-approved must degrade gracefully
rather than error.

Requirements

  • Config-driven per this project's convention: default disabled, enableable globally (env var)
    or per-repo (.gittensory.yml / repository_settings), independent of (but only meaningful when
    paired with) the feat(agent-actions): configurable per-contributor open PR/issue cap with auto-close over the limit #2270 cap being enabled.
  • Scope to v1: only fires after a deterministic closeKind: "contributor_cap" close (from feat(agent-actions): configurable per-contributor open PR/issue cap with auto-close over the limit #2270)
    succeeds. (Extending to the existing "blacklist" closeKind is a natural follow-up, not v1 here.)
  • On trigger: list in-progress/queued workflow runs for the closed PR's head SHA
    (GET /repos/{owner}/{repo}/actions/runs?head_sha={sha}&status=in_progress plus queued), then
    cancel each (POST .../actions/runs/{run_id}/cancel).
  • Must degrade gracefully when the installation hasn't granted actions: write (a 403/permission
    error from the list/cancel call must be caught, logged via the audit ledger, and must NOT block or
    fail the underlying close action that already succeeded).

Deliverables

  • Add actions: write to default_permissions in the App manifest (src/selfhost/setup-wizard.ts),
    plus operator-facing docs on re-approving the permission bump for existing installs.
  • New GitHub REST wrappers (alongside the existing src/github/app.ts / src/github/pr-actions.ts
    helpers) for listing workflow runs by head SHA and cancelling a run.
  • New settings field (e.g. contributorCapCancelCi?: boolean) threaded through the same
    migration → schema → RepositorySettingsFocusManifestSettings/parseSettingsOverride
    resolveEffectiveSettings chain used for every other per-repo toggle, plus a global env var
    default (e.g. CONTRIBUTOR_CAP_CANCEL_CI_DEFAULT).
  • Hook into the action executor: after a closeKind: "contributor_cap" close executes successfully,
    if enabled, cancel in-flight runs for that PR's head SHA.
  • Audit event (recordAuditEvent) for both outcomes: cancelled (with run count) and skipped/failed
    due to missing permission.
  • Tests: disabled (default) → no cancel attempt; enabled + contributor_cap close → runs cancelled;
    enabled + any other close kind → no cancel attempt; missing actions:write → soft-fails, close
    action itself still reports success.

Acceptance criteria

Expected outcome

Contributor-cap enforcement (#2270) actually saves the CI minutes it's meant to save, without
silently breaking (or requiring a forced upgrade for) self-hosted installs that haven't granted the
new Actions permission.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

Status
Done

Relationships

None yet

Development

No branches or pull requests

Issue actions