Skip to content
Arbinel

Cancel checks

Arbinel adds cancel buttons to the checks in a pull request’s merge box. A user can cancel one check, or all running checks with Cancel all. In Forgejo, you can only cancel whole runs from a repository’s Actions page.

Arbinel cancels Forgejo Actions jobs directly, with no configuration. For external CI systems, such as Woodpecker or Crow, Arbinel sends a signed cancel request that you configure in a [ci_cancel.<name>] section. This page is for site administrators and for people who connect a CI system.

The buttons appear on open pull requests in repositories that are not archived.

Check Shown as running when Who may cancel
Forgejo Actions job The job has not finished. Users with write access to Actions in the repository, while [actions] ENABLED = true.
External CI check Its commit status is pending and its target URL matches a configured CI system. Users with write access to the repository’s code.

Signed-out users see no buttons.

Every commit status has a target URL, the link behind Details in the merge box.

A status belongs to Forgejo Actions when its target URL has the form <repository>/actions/runs/<run>/jobs/<job>, the format that Forgejo Actions uses.

A status belongs to an external CI system when its target URL has the same scheme and host as the system’s TARGET_URL, and its path starts with the path of TARGET_URL. Arbinel checks the systems in the order of their sections and uses the first that matches.

Add one section per CI system:

[ci_cancel.crow]
TARGET_URL = https://ci.example.com/
URL = https://ci.example.com/api/hooks/arbinel/cancel
SECRET = a-long-random-shared-secret
TIMEOUT = 10s
Key Default Meaning
TARGET_URL none Prefix of the target URLs of the commit statuses this system reports. Must be an http or https URL.
URL none The endpoint that receives cancel requests. Must be an http or https URL.
SECRET none Shared secret that signs each request. At least 16 characters.
SECRET_URI none Reads the secret from a file instead, as file:/path/to/secret. Do not set both.
TIMEOUT 10s How long Arbinel waits for an answer.

The <name> part must contain only lower-case letters, digits, - and _, start with a letter or digit, and be at most 40 characters long. Arbinel logs an error and ignores a section that breaks any of these rules. An invalid section never stops the instance from starting.

Arbinel sends the request through the proxy in [proxy], if one is configured, and does not follow redirects.

Arbinel does not include a receiver for any CI system. The CI system needs an endpoint that accepts this request and cancels the pipelines.

When a user cancels checks of one CI system, Arbinel sends one POST request to its URL that lists all those checks:

POST /api/hooks/arbinel/cancel HTTP/1.1
Content-Type: application/json
User-Agent: Arbinel
X-Arbinel-Event: ci_cancel
X-Arbinel-Delivery: 7f3c9a52-2c4e-4c4b-9a43-0d6c1f6a8e21
X-Arbinel-Timestamp: 1767225600
X-Arbinel-Signature: sha256=<hex>
{
  "action": "cancel",
  "repository": {"id": 7, "full_name": "alice/app", "html_url": "https://git.example.com/alice/app"},
  "sha": "4b825dc642cb6eb9a060e54bf8d69288fbee4904",
  "pull_request": {"index": 12, "html_url": "https://git.example.com/alice/app/pulls/12"},
  "actor": {"id": 3, "login": "bob"},
  "checks": [
    {"context": "ci/crow/push/test", "target_url": "https://ci.example.com/repos/5/pipeline/81/1"}
  ]
}

The signature is the hex-encoded HMAC-SHA256 of <timestamp>.<body> with the shared secret as the key. X-Arbinel-Delivery is a new UUID for each request.

The receiver should:

  1. Recompute the signature and compare it in constant time.
  2. Reject requests whose timestamp is too old, to stop replays.
  3. Check that the pipelines behind the target URLs build the named repository.
  4. Check that the actor may cancel them, and cancel them as that user.
  5. Answer with any 2xx status once it has accepted the request.

Arbinel only checks that the actor has write access in Arbinel. The CI system is responsible for steps 3 and 4.

A Forgejo Actions job stops immediately.

For an external check, a 2xx answer means that the CI system accepted the cancel request. The check then shows Cancel requested, waiting for the CI to stop until the CI system reports a new status for it, or for at most 10 minutes. Arbinel stores this state in the cache, so it is shared between nodes only when they share the cache.

If the CI system sends any other answer or times out, or if a job cancel fails, Arbinel shows how many checks could not be cancelled. Arbinel logs the error with the name of the CI system.

When the pull request receives new commits while the page is open, Arbinel refuses the cancel and asks the user to reload the page.