feat(mirror): publish releases and their assets to another forge #1069
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
5 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1069
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1030-mirror-releases-with-assets"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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_tagslicing 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 -Kauth files, so tokens never enter/proc/cmdlineinstall -m600 /dev/null— the auth file is 0600 from birth, not chmod'd after%{http_code}check rather thancurl -f, so the API's error body reaches the logWhat 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.txtexists (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
since_tagdefaults tov1.0.0-alpha.0because 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
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
verify_checksumscosts 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-checkrc=0, zero warnings · register-checkrc=0· shellcheck clean on the extracted run block.Forgejo wiring correction
The reusable mirror now uses Forgejo-supported inherited secrets: both
workflow_callinterfaces expose only inputs, the caller job usessecrets: inherit, and the called step binds the Gitea target credential assecrets.MIRROR_TOKEN_GITEA_COM. The source credential remainssecrets.FORGEJO_TOKEN; both continue through 0600curl -Kauth files.The shipped called step was executed against a fake source/target API: a no-asset release completed with
created=1and 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.Fresh-CI refresh after the v0.56.1 tag repair was attempted against current main
5ece621bfe. The server-side rebase returned a conflict, so headb97641e589is 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.b97641e58987706124cbREQUEST_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 withforgejo-runner exec -n -d -E workflow_call -W .forgejo/workflows/mirror-release.yml, which logsinputs.verify_checksums != false -> falseand the called env asVERIFY_SUMS:false. The called reusable therefore disables checksum verification on the cut/call path, contrary to its documentedverify_checksumsdefault 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.
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.