Forgejo rejects username/password (Basic auth) for accounts with a
security key / passkey (WebAuthn) enrolled, responding 401 with
"Basic authorization is not allowed while having security keys enrolled".
This was misclassified as .invalidCredentials, showing "Invalid username
or password" and sending users in circles. Add a dedicated
.basicAuthBlockedBySecurityKey case that tells the user to use a token.
Also extract AuthenticationError into its own file.
- Add Attachment model with isImage computed property
- Add assets field to Issue, IssueComment, and PullRequest
- Add multipart/form-data upload support to ForgejoClient
- Add uploadIssueAttachment and uploadCommentAttachment to IssueService
Problem
- Merge failures currently collapse 405 and 409 responses to generic ServiceError cases, even when Forgejo returns a useful response body.
Change
- Keeps the existing notMergeable and mergeConflict fallbacks for empty responses.
- Preserves non-empty Forgejo response bodies as ServiceError.httpError for merge failures.
- Extracts the common JSON message field for clearer LocalizedError descriptions.
Tests
- DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test
Co-authored-by: Piotr Durlej <pdurlej@users.noreply.github.com>
Reviewed-on: https://codeberg.org/secana/ForgejoKit/pulls/3
Problem
- Callers currently need to inspect raw status codes to distinguish authentication, permission, not-found, and server failures.
Change
- Adds a small HTTPErrorCategory for 401, 403, 404, and 5xx responses.
- Exposes httpStatusCode and httpErrorCategory on ServiceError and AuthenticationError.
- Keeps the existing AuthenticationError cases intact and centralizes status-to-auth-error mapping.
Tests
- DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test
Co-authored-by: Piotr Durlej <pdurlej@users.noreply.github.com>
Reviewed-on: https://codeberg.org/secana/ForgejoKit/pulls/2
Reviewed-by: secana <secana@noreply.codeberg.org>
New model:
- WorkflowRun — mirrors Forgejo's ActionRun schema (id, title, status,
event, indexInRepo, commitSha, prettyRef, workflowId, created, updated,
started, stopped, durationNanos, htmlUrl, triggerUser, repository).
New service:
- WorkflowService
- fetchRuns(owner:repo:status:event:ref:workflowId:runNumber:headSha:page:limit:)
backed by GET /repos/{owner}/{repo}/actions/runs.
- fetchRun(owner:repo:runId:) backed by
GET /repos/{owner}/{repo}/actions/runs/{run_id}.
Experimental:
- fetchRunView(owner:repo:runIndex:jobIndex:logCursors:) backed by
Forgejo's web-UI route POST
/{owner}/{repo}/actions/runs/{runIndex}/jobs/{jobIndex}/attempt/{N}.
This is not part of /api/v1 and may change between Forgejo releases;
it lets clients render jobs, steps, and step logs (via WorkflowRunView,
WorkflowRunViewJob, WorkflowRunViewStep, WorkflowLogCursor types).
- ForgejoClient.discoverRedirectLocation(url:) helper that resolves
Forgejo's RedirectToLatestAttempt without consuming the redirect
target — used to find the latest attempt number before POSTing.
Co-authored-by: Voislav Vasiljevski <voislav@voioo.cz>
Reviewed-on: https://codeberg.org/secana/ForgejoKit/pulls/1
Reviewed-by: secana <secana@noreply.codeberg.org>