Closes the automation half of #45. Gitea → GitHub sync on every push to main and every v* tag.
Why a plain push, not Gitea's push mirror
A push mirror force-updates the refs it owns. If anyone ever clicks Merge on a GitHub PR, the next sync overwrites main, the PR still displays "Merged", the commit becomes unreachable, and nothing anywhere says so.
A non-force git push is rejected as non-fast-forward the moment that happens — turning a silent data-loss trap into a red CI run in a place we already look. That is the whole point; do not add --force.
Also do not add GitHub branch protection to the mirror: protection rules block the mirror's legitimate pushes too, breaking normal syncing to catch an abnormal case.
Secret naming
The secret is PAT_GH, not GITHUB_MIRROR_PAT as originally written in #45. Gitea reserves the GITHUB_ and GITEA_ prefixes for its own injected variables and refuses to create secrets using them. Worth remembering for any future workflow that needs to authenticate outward.
It is a GitHub PAT (repo + workflow scope — workflow is required because this pushes .github/workflows/), stored as a Gitea Actions secret. The direction confuses easily: the Gitea runner is the one authenticating to GitHub.
The step fails loudly with a named remediation if the secret is unset, rather than producing a confusing git auth error.
Test plan
YAML parses
PAT_GH confirmed present in the repo's Actions secrets
Mirror already populated by an equivalent manual push, so main is a fast-forward — this merge is the first automated run
Verify the run pushes and that GitHub receives the merge commit
Notes
The mirror is already live and working — I pushed main by hand once the repo existed, which is what triggered the first multi-OS matrix run. This PR only removes the manual step.
## Summary
Closes the automation half of #45. Gitea → GitHub sync on every push to `main` and every `v*` tag.
## Why a plain push, not Gitea's push mirror
A push mirror **force-updates** the refs it owns. If anyone ever clicks **Merge** on a GitHub PR, the next sync overwrites `main`, the PR still displays "Merged", the commit becomes unreachable, and nothing anywhere says so.
A non-force `git push` is **rejected** as non-fast-forward the moment that happens — turning a silent data-loss trap into a red CI run in a place we already look. That is the whole point; do not add `--force`.
Also do **not** add GitHub branch protection to the mirror: protection rules block the mirror's legitimate pushes too, breaking normal syncing to catch an abnormal case.
## Secret naming
The secret is **`PAT_GH`**, not `GITHUB_MIRROR_PAT` as originally written in #45. **Gitea reserves the `GITHUB_` and `GITEA_` prefixes** for its own injected variables and refuses to create secrets using them. Worth remembering for any future workflow that needs to authenticate outward.
It is a **GitHub** PAT (`repo` + `workflow` scope — `workflow` is required because this pushes `.github/workflows/`), stored as a **Gitea** Actions secret. The direction confuses easily: the Gitea runner is the one authenticating *to* GitHub.
The step fails loudly with a named remediation if the secret is unset, rather than producing a confusing git auth error.
## Test plan
- [x] YAML parses
- [x] `PAT_GH` confirmed present in the repo's Actions secrets
- [x] Mirror already populated by an equivalent manual push, so `main` is a fast-forward — this merge is the first automated run
- [ ] Verify the run pushes and that GitHub receives the merge commit
## Notes
The mirror is already live and working — I pushed `main` by hand once the repo existed, which is what triggered the first multi-OS matrix run. This PR only removes the manual step.
A plain non-force git push rather than Gitea's built-in push mirror. A
push mirror force-updates the refs it owns, so a Merge clicked on a GitHub
PR would be silently overwritten on the next sync -- the PR still reading
'Merged' while its commit became unreachable. A non-force push is rejected
instead, which turns that into a red CI run.
Secret is PAT_GH, not GITHUB_MIRROR_PAT: Gitea reserves the GITHUB_ and
GITEA_ prefixes for its own injected variables and refuses secrets using
them.
@jaredKodor PR Review — #54: ci: mirror main and tags to the GitHub mirror
Summary
Single-file addition (.gitea/workflows/mirror-github.yml), +43 lines. Sets up automated Gitea → GitHub mirror on push to main and v* tags.
Findings
✅ Good
Well-documented rationale in the YAML header explaining why plain git push is preferred over Gitea built-in push mirrors (silent data-loss prevention)
Safe failure mode: non-fast-forward rejection turns a dangerous overwrite into a visible red CI run
Clear secret naming: PAT_GH avoids Gitea-reserved prefixes (GITHUB_, GITEA_). Good call documenting this gotcha
Fail-fast on missing secret: explicit check with remediation message rather than cryptic git auth error
CI is green — PR run (ID:1966) shows conclusion: success
Mergeable: no conflicts with main
⚠️ Observations (not blockers)
Test plan checkbox unchecked: The last item (Verify the run pushes and that GitHub receives the merge commit) is still pending. Since CI passed on the PR event, the actual mirror push won’t run until merge. You may want to verify after merging.
Token in URL: The git push "https://x-access-token:${PAT_GH}@..." pattern works but could leak the token in process listings (ps aux). Consider using git remote set-url with a temporary config or GIT_ASKPASS for cleaner credential handling. Low risk since this runs in an ephemeral CI container.
No rate-limit handling: If GitHub API rate-limits the push (unlikely for PAT-authenticated pushes, but possible), there’s no retry logic. Acceptable for now given low push frequency.
Verdict
LGTM — Clean, well-reasoned CI addition. The anti-pattern warnings (no --force, no branch protection on the mirror) are thoughtfully documented. Ready to merge once you verify the post-merge push.
Review by Kodor via cron job — 2026-08-09
@jared **Kodor PR Review — #54: ci: mirror main and tags to the GitHub mirror**
## Summary
Single-file addition (`.gitea/workflows/mirror-github.yml`), +43 lines. Sets up automated Gitea → GitHub mirror on push to `main` and `v*` tags.
## Findings
### ✅ Good
- **Well-documented rationale** in the YAML header explaining why plain `git push` is preferred over Gitea built-in push mirrors (silent data-loss prevention)
- **Safe failure mode**: non-fast-forward rejection turns a dangerous overwrite into a visible red CI run
- **Clear secret naming**: `PAT_GH` avoids Gitea-reserved prefixes (`GITHUB_`, `GITEA_`). Good call documenting this gotcha
- **Fail-fast on missing secret**: explicit check with remediation message rather than cryptic git auth error
- **CI is green** — PR run (ID:1966) shows `conclusion: success`
- **Mergeable**: no conflicts with main
### ⚠️ Observations (not blockers)
1. **Test plan checkbox unchecked**: The last item (`Verify the run pushes and that GitHub receives the merge commit`) is still pending. Since CI passed on the PR event, the actual mirror push won’t run until merge. You may want to verify after merging.
2. **Token in URL**: The `git push "https://x-access-token:${PAT_GH}@..."` pattern works but could leak the token in process listings (`ps aux`). Consider using `git remote set-url` with a temporary config or `GIT_ASKPASS` for cleaner credential handling. Low risk since this runs in an ephemeral CI container.
3. **No rate-limit handling**: If GitHub API rate-limits the push (unlikely for PAT-authenticated pushes, but possible), there’s no retry logic. Acceptable for now given low push frequency.
## Verdict
**LGTM** — Clean, well-reasoned CI addition. The anti-pattern warnings (no `--force`, no branch protection on the mirror) are thoughtfully documented. Ready to merge once you verify the post-merge push.
---
*Review by Kodor via cron job — 2026-08-09*
jared
merged commit d74ecdd4a5 into main2026-08-09 09:04:29 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Closes the automation half of #45. Gitea → GitHub sync on every push to
mainand everyv*tag.Why a plain push, not Gitea's push mirror
A push mirror force-updates the refs it owns. If anyone ever clicks Merge on a GitHub PR, the next sync overwrites
main, the PR still displays "Merged", the commit becomes unreachable, and nothing anywhere says so.A non-force
git pushis rejected as non-fast-forward the moment that happens — turning a silent data-loss trap into a red CI run in a place we already look. That is the whole point; do not add--force.Also do not add GitHub branch protection to the mirror: protection rules block the mirror's legitimate pushes too, breaking normal syncing to catch an abnormal case.
Secret naming
The secret is
PAT_GH, notGITHUB_MIRROR_PATas originally written in #45. Gitea reserves theGITHUB_andGITEA_prefixes for its own injected variables and refuses to create secrets using them. Worth remembering for any future workflow that needs to authenticate outward.It is a GitHub PAT (
repo+workflowscope —workflowis required because this pushes.github/workflows/), stored as a Gitea Actions secret. The direction confuses easily: the Gitea runner is the one authenticating to GitHub.The step fails loudly with a named remediation if the secret is unset, rather than producing a confusing git auth error.
Test plan
PAT_GHconfirmed present in the repo's Actions secretsmainis a fast-forward — this merge is the first automated runNotes
The mirror is already live and working — I pushed
mainby hand once the repo existed, which is what triggered the first multi-OS matrix run. This PR only removes the manual step.@jared Kodor PR Review — #54: ci: mirror main and tags to the GitHub mirror
Summary
Single-file addition (
.gitea/workflows/mirror-github.yml), +43 lines. Sets up automated Gitea → GitHub mirror on push tomainandv*tags.Findings
✅ Good
git pushis preferred over Gitea built-in push mirrors (silent data-loss prevention)PAT_GHavoids Gitea-reserved prefixes (GITHUB_,GITEA_). Good call documenting this gotchaconclusion: success⚠️ Observations (not blockers)
Verify the run pushes and that GitHub receives the merge commit) is still pending. Since CI passed on the PR event, the actual mirror push won’t run until merge. You may want to verify after merging.git push "https://x-access-token:${PAT_GH}@..."pattern works but could leak the token in process listings (ps aux). Consider usinggit remote set-urlwith a temporary config orGIT_ASKPASSfor cleaner credential handling. Low risk since this runs in an ephemeral CI container.Verdict
LGTM — Clean, well-reasoned CI addition. The anti-pattern warnings (no
--force, no branch protection on the mirror) are thoughtfully documented. Ready to merge once you verify the post-merge push.Review by Kodor via cron job — 2026-08-09