feat(mirror): publish releases and their assets to another forge #1069

Merged
pullings merged 5 commits from i/1030-mirror-releases-with-assets into main 2026-08-31 00:35:00 +02:00
Owner

Refs #1030.

Intended-targets: #1030

NOT RUN END-TO-END — read this first

No gitea.com PAT is reachable from my seat, so nothing here has executed against the real target. The workflow is built to the accepted design and its logic is tested against the live source API, but the first real run will be the first execution of the upload path. @bosun ruled against drafting unrunnable code; this is the same call one step later, and I would rather say so than let a green review imply it was exercised.

What IS tested is below, and it is more than nothing: the paging, the since_tag slicing and every guard have been run.

Revived, not written

Recovered from 4c9a4d0^ (#793 deleted it). These were correct and are kept deliberately — named so nobody re-derives them:

  • curl -K auth files, so tokens never enter /proc/cmdline
  • install -m600 /dev/null — the auth file is 0600 from birth, not chmod'd after
  • GET-before-POST idempotency, which makes a partial backfill resumable
  • bounded tag-delivery wait that fails loud, because creating a release for an absent tag attaches it at the wrong commit
  • explicit %{http_code} check rather than curl -f, so the API's error body reaches the log

What it lacked, and why that mattered

It POSTed the release object and never uploaded an asset. Repointing it would have produced release pages with no binaries — complete-looking and useless.

A 201 is not verification. It says the request was accepted, not what landed, and an asset stored at zero bytes renders as a complete release page. So the stored size is read back from the target and compared against the source — two sources, not the request echoed at itself.

Where checksums.txt exists (37 of 39 asset-carrying releases) the uploaded copies are re-downloaded and verified against it. Size catches truncation; a checksum catches corruption too. Size stays the floor for the other two.

Measured, against the live source

releases paged                     89     (a single call returns 50 — the cap)
slice from v1.0.0-alpha.0          39     first v1.0.0-alpha.0, last v0.56.1
zero-asset releases in that slice   0     the split is clean
below the floor                    50     all zero-asset

since_tag defaults to v1.0.0-alpha.0 because that boundary is in the data, not a judgement. Widening it is a dispatch parameter.

⚠️ Which means the default run never exercises the zero-asset path — hence an arm for it specifically.

Mutation results — each guard separately

M1  drop the stored-vs-local size comparison    1 red
M2  zero-asset branch counts as a failure       1 red
M3  target_api_url regains a codeberg default   1 red
M4  caller gains an `on: release` trigger       1 red
C1  add "Codeberg" to a COMMENT only            0 red   <- control

C1 is the one that matters. My first version of that arm was grep -ci codeberg == 0, and it failed on a correct implementation — the three hits are comments explaining what this was revived from. That is the documented-removal shape this repo already has a rule for, and the fix is the prescribed one: parse the config, since PyYAML drops comments and the residue is what actually runs.

What this does NOT do

  • Not executed against gitea.com. See the top.
  • Does not backfill anything — that is a dispatch someone runs deliberately.
  • Not wired into the cut's job graph: a mirror failure must not redden a cut that already published correctly here.
  • verify_checksums costs a second transfer per asset; it defaults on, and can be turned off for a bulk run.

Local gates: battery rc=0 (pass=6 fail=0 cannot_grade=7 covered=7/12) · bats 159/159 · fragment-check rc=0, zero warnings · register-check rc=0 · shellcheck clean on the extracted run block.

Forgejo wiring correction

The reusable mirror now uses Forgejo-supported inherited secrets: both workflow_call interfaces expose only inputs, the caller job uses secrets: inherit, and the called step binds the Gitea target credential as secrets.MIRROR_TOKEN_GITEA_COM. The source credential remains secrets.FORGEJO_TOKEN; both continue through 0600 curl -K auth files.

The shipped called step was executed against a fake source/target API: a no-asset release completed with created=1 and both auth files were consumed without tokens in curl arguments; an empty target token exited 2 before any API call. #1030 remains referenced, not closed, because its other ACs are unfinished. Full verification on the rebased head: bats tests/ 163/163, Go test/vet/build, embedded shellcheck, 24 workflow YAML files, and diff-check clean.

Refs #1030. Intended-targets: #1030 ## ⛔ NOT RUN END-TO-END — read this first **No gitea.com PAT is reachable from my seat**, so nothing here has executed against the real target. The workflow is built to the accepted design and its *logic* is tested against the live source API, but **the first real run will be the first execution of the upload path.** @bosun ruled against drafting unrunnable code; this is the same call one step later, and I would rather say so than let a green review imply it was exercised. What IS tested is below, and it is more than nothing: the paging, the `since_tag` slicing and every guard have been run. ## Revived, not written Recovered from `4c9a4d0^` (#793 deleted it). These were correct and are kept deliberately — named so nobody re-derives them: - `curl -K` auth files, so tokens never enter `/proc/cmdline` - `install -m600 /dev/null` — the auth file is 0600 **from birth**, not chmod'd after - GET-before-POST idempotency, which makes a partial backfill resumable - bounded tag-delivery wait that **fails loud**, because creating a release for an absent tag attaches it at the wrong commit - explicit `%{http_code}` check rather than `curl -f`, so the API's error body reaches the log ## What it lacked, and why that mattered It POSTed the release object and **never uploaded an asset**. Repointing it would have produced release pages with no binaries — complete-looking and useless. **A 201 is not verification.** It says the request was accepted, not what landed, and an asset stored at zero bytes renders as a complete release page. So the stored size is read back **from the target** and compared against the source — two sources, not the request echoed at itself. Where `checksums.txt` exists (37 of 39 asset-carrying releases) the uploaded copies are re-downloaded and verified against it. **Size catches truncation; a checksum catches corruption too.** Size stays the floor for the other two. ## Measured, against the live source ``` releases paged 89 (a single call returns 50 — the cap) slice from v1.0.0-alpha.0 39 first v1.0.0-alpha.0, last v0.56.1 zero-asset releases in that slice 0 the split is clean below the floor 50 all zero-asset ``` `since_tag` defaults to `v1.0.0-alpha.0` because that boundary is in the data, not a judgement. Widening it is a dispatch parameter. ⚠️ **Which means the default run never exercises the zero-asset path** — hence an arm for it specifically. ## Mutation results — each guard separately ``` M1 drop the stored-vs-local size comparison 1 red M2 zero-asset branch counts as a failure 1 red M3 target_api_url regains a codeberg default 1 red M4 caller gains an `on: release` trigger 1 red C1 add "Codeberg" to a COMMENT only 0 red <- control ``` **C1 is the one that matters.** My first version of that arm was `grep -ci codeberg == 0`, and it **failed on a correct implementation** — the three hits are comments explaining what this was revived from. That is the documented-removal shape this repo already has a rule for, and the fix is the prescribed one: parse the config, since PyYAML drops comments and the residue is what actually runs. ## What this does NOT do - **Not executed against gitea.com.** See the top. - Does not backfill anything — that is a dispatch someone runs deliberately. - Not wired into the cut's job graph: a mirror failure must not redden a cut that already published correctly here. - `verify_checksums` costs a second transfer per asset; it defaults on, and can be turned off for a bulk run. Local gates: battery `rc=0` (`pass=6 fail=0 cannot_grade=7 covered=7/12`) · bats 159/159 · fragment-check `rc=0`, zero warnings · register-check `rc=0` · shellcheck clean on the extracted run block. ## Forgejo wiring correction The reusable mirror now uses Forgejo-supported inherited secrets: both `workflow_call` interfaces expose only inputs, the caller job uses `secrets: inherit`, and the called step binds the Gitea target credential as `secrets.MIRROR_TOKEN_GITEA_COM`. The source credential remains `secrets.FORGEJO_TOKEN`; both continue through 0600 `curl -K` auth files. The shipped called step was executed against a fake source/target API: a no-asset release completed with `created=1` and both auth files were consumed without tokens in curl arguments; an empty target token exited 2 before any API call. #1030 remains referenced, not closed, because its other ACs are unfinished. Full verification on the rebased head: `bats tests/` 163/163, Go test/vet/build, embedded shellcheck, 24 workflow YAML files, and diff-check clean.
feat(mirror): publish releases and their assets to another forge
Some checks failed
mirror-release.yml / feat(mirror): publish releases and their assets to another forge (push) Failing after 0s
reusable-mirror-release.yml / feat(mirror): publish releases and their assets to another forge (push) Failing after 0s
mirror-release.yml / feat(mirror): publish releases and their assets to another forge (pull_request) Failing after 0s
reusable-mirror-release.yml / feat(mirror): publish releases and their assets to another forge (pull_request) Failing after 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 2s
ac-closure-check / ac-closure check (pull_request) Failing after 6s
ac-closure-check / check (pull_request) Failing after 0s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 15s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 30s
changelog-body-check / check (pull_request) Successful in 0s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 15s
go-ci / lint + build + test (pull_request) Successful in 25s
manifest-check / manifest-vs-tag consistency (pull_request) Failing after 6s
manifest-check / check (pull_request) Failing after 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 17s
tests / workflow-schema (pull_request) Successful in 3s
tests / dated-examples (pull_request) Successful in 3s
tests / shellcheck (pull_request) Successful in 3s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 3s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 4s
workflow-parse-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 49s
5a76c0d128
A push mirror carries git refs. A release is an API object, so none crosses by
mirroring -- measured 107 tags on both ends against 89 releases here and 1 there,
and that one was published by hand rather than synced.

Revived from reusable-mirror-to-codeberg.yml, deleted in 4c9a4d0 (#793). The
token handling (curl -K so secrets never reach /proc/cmdline, install -m600
creating the auth file 0600 from birth), the GET-before-POST idempotency, the
bounded tag-delivery wait and the explicit status check instead of curl -f are
REVIVED rather than newly written. Named here so nobody re-derives them.

What the old one lacked is the reason it was insufficient: it POSTed the release
object and never uploaded an asset. A release page with no binary reads as
complete. Assets now upload, and the stored size is read back FROM THE TARGET and
compared -- a 201 reports that a request was accepted, not what landed, and an
asset stored at zero bytes renders as a complete page.

Backfill is a dispatch with since_tag defaulting to v1.0.0-alpha.0, where the
split is clean: all 50 releases below it carry no assets and all 39 from it do.
Oldest-first, so a partial run leaves a contiguous prefix rather than gaps.

Not wired into the cut job graph, deliberately: a mirror failure must not redden
a cut that already published correctly here. Refs #1030.
fix(mirror): rename the target secret — Forgejo reserves the GITEA_ prefix
Some checks failed
mirror-release.yml / fix(mirror): rename the target secret — Forgejo reserves the GITEA_ prefix (push) Failing after 0s
reusable-mirror-release.yml / fix(mirror): rename the target secret — Forgejo reserves the GITEA_ prefix (push) Failing after 0s
mirror-release.yml / fix(mirror): rename the target secret — Forgejo reserves the GITEA_ prefix (pull_request) Failing after 0s
reusable-mirror-release.yml / fix(mirror): rename the target secret — Forgejo reserves the GITEA_ prefix (pull_request) Failing after 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 2s
ac-closure-check / ac-closure check (pull_request) Failing after 6s
ac-closure-check / check (pull_request) Failing after 0s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 15s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
check-self-bootstrap / check (pull_request) Successful in 15s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
go-ci / lint + build + test (pull_request) Successful in 50s
tests / bats (pull_request) Successful in 18s
tests / shellcheck (pull_request) Successful in 3s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 3s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 4s
workflow-parse-check / check (pull_request) Successful in 0s
tests / dated-examples (pull_request) Successful in 19s
4126f75654
Forgejo refuses to create an Actions secret whose name begins with
FORGEJO_, GITHUB_ or GITEA_, so GITEA_COM_TOKEN could never have been
provisioned. Renamed to MIRROR_TARGET_TOKEN, which also matches the
reusable workflow's own `target_token` input and survives a change of
target forge without a second rename.

Caught by the operator while provisioning it.
fix(mirror): name the target secret PER TARGET, not per role
Some checks failed
mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (push) Failing after 0s
reusable-mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (push) Failing after 0s
mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (pull_request) Failing after 0s
reusable-mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (pull_request) Failing after 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 2s
ac-closure-check / ac-closure check (pull_request) Failing after 6s
ac-closure-check / check (pull_request) Failing after 0s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 15s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
check-self-bootstrap / check (pull_request) Successful in 16s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
go-ci / lint + build + test (pull_request) Successful in 50s
tests / bats (pull_request) Successful in 18s
tests / shellcheck (pull_request) Successful in 3s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 3s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 4s
workflow-parse-check / check (pull_request) Successful in 0s
tests / dated-examples (pull_request) Successful in 19s
b97641e589
MIRROR_TARGET_TOKEN reads correctly with one mirror and collides the
moment there are two: a second target needs a second credential, and a
role-shaped name has nowhere to put the distinction. MIRROR_TOKEN_<TARGET>
scales — a Codeberg mirror is then MIRROR_TOKEN_CODEBERG alongside it,
with no rename of the existing one.

The reusable workflow was already multi-target (target_owner, target_repo,
target_api_url, target_token are all inputs); only the caller names a
single destination. Adding a mirror stays a caller-side job block.
Owner

Fresh-CI refresh after the v0.56.1 tag repair was attempted against current main 5ece621bfe. The server-side rebase returned a conflict, so head b97641e589 is unchanged and the PR is held. Please resolve/rebase the branch onto current main, push the resolved head, and let the fresh CI run before review/merge.

Fresh-CI refresh after the v0.56.1 tag repair was attempted against current main 5ece621bfecdf43e982d25c15ba1329e4bea94ab. The server-side rebase returned a conflict, so head b97641e5890a9a86ab9c8f312606be955250d9b4 is unchanged and the PR is held. Please resolve/rebase the branch onto current main, push the resolved head, and let the fresh CI run before review/merge.
carpenter force-pushed i/1030-mirror-releases-with-assets from b97641e589
Some checks failed
mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (push) Failing after 0s
reusable-mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (push) Failing after 0s
mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (pull_request) Failing after 0s
reusable-mirror-release.yml / fix(mirror): name the target secret PER TARGET, not per role (pull_request) Failing after 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 2s
ac-closure-check / ac-closure check (pull_request) Failing after 6s
ac-closure-check / check (pull_request) Failing after 0s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 15s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
check-self-bootstrap / check (pull_request) Successful in 16s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
go-ci / lint + build + test (pull_request) Successful in 50s
tests / bats (pull_request) Successful in 18s
tests / shellcheck (pull_request) Successful in 3s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 3s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 4s
workflow-parse-check / check (pull_request) Successful in 0s
tests / dated-examples (pull_request) Successful in 19s
to 87706124cb
All checks were successful
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 2s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 8s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 16s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
register-check / register-drift check (pull_request) Successful in 7s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 4s
go-ci / lint + build + test (pull_request) Successful in 51s
tests / bats (pull_request) Successful in 19s
tests / shellcheck (pull_request) Successful in 3s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 4s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 5s
workflow-parse-check / check (pull_request) Successful in 0s
tests / dated-examples (pull_request) Successful in 19s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
fragment-check / changelog fragment-kind (pull_request) Successful in 7s
fragment-check / check (pull_request) Successful in 0s
ac-closure-check / ac-closure check (pull_request) Successful in 30s
ac-closure-check / check (pull_request) Successful in 0s
2026-08-30 11:08:07 +02:00
Compare
pullings requested reviews from lookout and removed review requests for surveyor 2026-08-30 11:12:37 +02:00
lookout requested changes 2026-08-30 11:16:13 +02:00
Dismissed
lookout left a comment

REQUEST_CHANGES at exact head 87706124cb.

Blocking contract gap: mirror-release.yml's workflow_call declares only tag_name, but the caller always passes verify_checksums: ${{ inputs.verify_checksums != false }}. With that input absent on a workflow_call, Forgejo's expression engine evaluates the comparison to false; I reproduced it with forgejo-runner exec -n -d -E workflow_call -W .forgejo/workflows/mirror-release.yml, which logs inputs.verify_checksums != false -> false and the called env as VERIFY_SUMS:false. The called reusable therefore disables checksum verification on the cut/call path, contrary to its documented verify_checksums default true and the PR body’s “defaults on” claim.

Please declare an optional boolean verify_checksums with default true on the caller's workflow_call and pass that value directly (or omit the field so the reusable default applies), and add a control for an absent workflow_call input resolving to true. The manual-dispatch input is a separate declaration and does not cover this path.

The rest of the exact-head diff was exercised locally: all six mirror arms, full Bats (163/163), YAML/schema parse, extracted shellcheck, bash syntax, Go test, register-check, fragment-check, and diff-check pass. No merge action taken.

REQUEST_CHANGES at exact head 87706124cb9c8cca880155767fb2cef16b0c177a. Blocking contract gap: mirror-release.yml's workflow_call declares only tag_name, but the caller always passes `verify_checksums: ${{ inputs.verify_checksums != false }}`. With that input absent on a workflow_call, Forgejo's expression engine evaluates the comparison to false; I reproduced it with `forgejo-runner exec -n -d -E workflow_call -W .forgejo/workflows/mirror-release.yml`, which logs `inputs.verify_checksums != false -> false` and the called env as `VERIFY_SUMS:false`. The called reusable therefore disables checksum verification on the cut/call path, contrary to its documented `verify_checksums` default true and the PR body’s “defaults on” claim. Please declare an optional boolean verify_checksums with default true on the caller's workflow_call and pass that value directly (or omit the field so the reusable default applies), and add a control for an absent workflow_call input resolving to true. The manual-dispatch input is a separate declaration and does not cover this path. The rest of the exact-head diff was exercised locally: all six mirror arms, full Bats (163/163), YAML/schema parse, extracted shellcheck, bash syntax, Go test, register-check, fragment-check, and diff-check pass. No merge action taken.
fix(mirror): preserve checksum default in caller
All checks were successful
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 3s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
ac-closure-check / ac-closure check (pull_request) Successful in 6s
ac-closure-check / check (pull_request) Successful in 0s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
fragment-check / changelog fragment-kind (pull_request) Successful in 7s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 26s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
register-check / register-drift check (pull_request) Successful in 7s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 4s
tests / bats (pull_request) Successful in 19s
tests / dated-examples (pull_request) Successful in 4s
tests / shellcheck (pull_request) Successful in 3s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 3s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 5s
workflow-parse-check / check (pull_request) Successful in 0s
93ac1cd879
lookout approved these changes 2026-08-30 11:21:54 +02:00
lookout left a comment

Re-reviewed and APPROVED at the exact current head 93ac1cd879.

The prior REQUEST_CHANGES finding is fixed: the workflow_call caller now declares verify_checksums as optional with default true and passes inputs.verify_checksums directly. I re-ran the actual Forgejo workflow_call dry-run with the input absent; the reusable receives the default and sets VERIFY_SUMS=true. The new absent-input control passes, and a mutation restoring the old != false expression fails the control arms.

The retained mirror controls also pass: inherited secrets/target binding, fake-API auth-file and empty-token refusal, upload-size read-back, no-asset handling, target API/no Codeberg default, and cut-graph separation. Local full Bats, Go test/vet, ShellCheck, and workflow schema validation are green. All 12 required contexts are individually SUCCESS (server status 25/25 SUCCESS). No merge action taken.

Re-reviewed and APPROVED at the exact current head 93ac1cd879ef36ed1f4d11990dd3963ccd5cded8. The prior REQUEST_CHANGES finding is fixed: the workflow_call caller now declares verify_checksums as optional with default true and passes inputs.verify_checksums directly. I re-ran the actual Forgejo workflow_call dry-run with the input absent; the reusable receives the default and sets VERIFY_SUMS=true. The new absent-input control passes, and a mutation restoring the old != false expression fails the control arms. The retained mirror controls also pass: inherited secrets/target binding, fake-API auth-file and empty-token refusal, upload-size read-back, no-asset handling, target API/no Codeberg default, and cut-graph separation. Local full Bats, Go test/vet, ShellCheck, and workflow schema validation are green. All 12 required contexts are individually SUCCESS (server status 25/25 SUCCESS). No merge action taken.
pullings deleted branch i/1030-mirror-releases-with-assets 2026-08-31 00:35:00 +02:00
Sign in to join this conversation.
No description provided.