fix(collector): Forgejo 16 Actions shapes + bind the forge read token (U-I2b) #1

Merged
jsutter merged 3 commits from ditdash-u-i2b-forgejo16 into main 2026-10-08 07:34:20 +00:00
Owner

Run selection accepts Forgejo (status=success) and GitHub (completed+success); artifacts accept bare arrays; archive_download_url preferred; expired skipped. End-to-end stub-server test of refresh(). Manifest binds DITDASH_FORGE_TOKEN (ditdash-reader). Critic: approve-with-fixes; R1/R4 fixed.

Run selection accepts Forgejo (status=success) and GitHub (completed+success); artifacts accept bare arrays; archive_download_url preferred; expired skipped. End-to-end stub-server test of refresh(). Manifest binds DITDASH_FORGE_TOKEN (ditdash-reader). Critic: approve-with-fixes; R1/R4 fixed.
The reader required GitHub's status=="completed" && conclusion=="success"
and {"artifacts":[...]} listings, so on the live Forgejo 16.0.4 it found
neither a run nor its bundle: a finished run reports status=="success" with
conclusion null, and the per-run artifacts endpoint answers with a bare
JSON array. Accept both shapes — run selection takes either success form,
the artifact listing takes bare-array or object, and the download URL
prefers archive_download_url, then download_url, then url + "/zip" (a
non-expired named artifact; the expired-only case names that as the miss).

Selection is factored into pure helpers (run_succeeded, select_run_id,
artifact_items, pick_bundle_download, resolve_download_url) with unit
tests on the observed forge fixtures plus GitHub-shaped fixtures.

Also, in this file only: Snapshot's Default derives (clippy::derivable_impls)
and clock() passes the fn to unwrap_or_else (clippy::redundant_closure) —
both were pre-existing -D warnings blockers — and the file is rustfmt
normalized, clearing its 19 pre-existing fmt hunks. Crate-wide clippy/fmt
still fail on surface.rs, views.rs, and tests/ (identical at base; outside
this contract's files owned).

Assisted-by: worker-local:sage-ai/sage
R1: a loopback TcpListener stub serves the observed Forgejo runs listing
(a newer running row that selection must skip), the bare-array artifacts
listing whose archive_download_url points back at the stub, and a small
zip (manifest.json + one surface file) built with the zip crate. The test
drives Collector::refresh() through the real ureq transport and asserts:
the run id returns, cache/<run>/manifest.json lands (and the surface
file), every request carried Authorization: token <t>, a second refresh
of the same run re-hits neither the artifacts nor the zip endpoint (the
cache short-circuit), and a 404 on the artifacts call surfaces the
failing URL and status and leaves no cached bundle. No external network.

R4: artifact_items is module-private (its only readers are refresh_forge
and the in-module tests).

Assisted-by: worker-local:sage-ai/sage
The bundle reader's token: restricted forge account ditdash-reader, collaborator read on deepnet/ops only; custody secret/deepnet/apps/ditdash/forge-read-token.

Assisted-by: deepnet:anthropic/claude-opus-5-5
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
deepnet/ditdash!1
No description provided.