• Stable

    GiteaMirror released this 2026-05-19 02:21:18 -05:00 | 1 commits to main since this release

    📅 Originally published on GitHub: Tue, 19 May 2026 07:21:42 GMT
    🏷️ Git tag created: Tue, 19 May 2026 07:21:18 GMT

    What's new

    feat: Change password and Change email from the UI (#292)

    Resolves discussion #291. Better Auth's change-password / change-email endpoints have always been exposed server-side, but there was no way to reach them from the web UI.

    The avatar dropdown in the header now shows:

    • Change password — opens a dialog with current/new/confirm fields and a "Sign out other devices" checkbox (defaults on, calls Better Auth's `revokeOtherSessions: true` — verified end-to-end that other sessions are invalidated immediately).
    • Change email — opens a dialog with the new email field. The dropdown updates to show the new address as soon as the change succeeds.

    SSO-only users (no local password) have the Change password item hidden. The check uses `GET /api/auth/list-accounts` to look for a `credential` provider; if the probe errors it fails open rather than locking anyone out.

    This required enabling `user.changeEmail` in Better Auth with `updateEmailWithoutVerification: true` — safe in this app because email verification isn't on and there's no email sender wired up.

    ci: pin third-party GitHub Actions to commit SHAs (#293)

    In response to the supply-chain attack pattern that recently hit `actions-cool/issues-helper` and `actions-cool/maintain-one-comment`, and `tj-actions/changed-files` before that.

    Tags are mutable. A compromised maintainer can force-move `@v3` to point at malicious code, and every workflow using the tag picks it up on the next run. Pinning to a 40-char commit SHA makes the reference immutable.

    This release pins the highest-risk subset:

    • `nix-build.yml` — two `@main` branch refs (worse than tags, since they move on every push) → pinned to release SHAs for `v22` / `v13`.
    • `docker-build.yml` — every third-party action (`docker/setup-buildx`, `docker/login`, `docker/metadata`, `docker/build-push`, `docker/scout`) now references a SHA with a trailing `# vX.Y.Z` comment for readability.

    This is the workflow that holds the GHCR push token, Docker Hub login, and Scout API token — so it's the one with the largest blast radius if compromised.

    First-party `actions/*` and `github/codeql-action` are left on tags for now; they're a separate, lower-risk follow-up. Dependabot for the `github-actions` ecosystem is recommended next so SHA pins still get auto-bumped.

    `chore`: bump and digest-pin Bun base image to 1.3.14 (#295)

    Same hardening principle, applied to the Dockerfile:

    • Bun `1.3.13-debian` → `1.3.14-debian` (released 2026-05-13)
    • Pinned to digest: `@sha256:9dba1a1b...db6f` (multi-arch — `linux/amd64` and `linux/arm64`)
    • Applies to both the `base` and `runner` stages in the Dockerfile

    A tag on Docker Hub is just as mutable as a tag on GitHub; pinning to the digest closes the same class of attack at the container layer.

    Downloads
  • Stable

    GiteaMirror released this 2026-05-16 01:33:53 -05:00 | 5 commits to main since this release

    📅 Originally published on GitHub: Sat, 16 May 2026 06:44:56 GMT
    🏷️ Git tag created: Sat, 16 May 2026 06:33:53 GMT

    What's new

    chore: patch 9 HIGH-severity npm CVE alerts (#289)

    The weekly Docker Scout scan surfaced 9 HIGH alerts in transitive npm deps. All have fixed versions upstream; pinned via package.json overrides.

    Package Bumped to CVEs
    @xmldom/xmldom 0.8.13 CVE-2026-41672, 41673, 41674, 41675
    devalue 5.8.1 CVE-2026-42570
    kysely 0.28.17 CVE-2026-44635
    fast-uri 3.1.2 CVE-2026-6321, 6322
    fast-xml-builder 1.1.7 CVE-2026-44665

    chore: prune npm overrides that are no longer load-bearing (#290)

    Internal cleanup. Removed 5 stale overrides (defu, fast-xml-parser, node-forge, rollup, svgo) whose constraints are now satisfied naturally by the transitive dep graph. Verified by removing each and confirming the resolved version and tree shape are identical.

    No behavior change — only package.json housekeeping.

    Note on remaining Docker Scout alerts

    The remaining HIGH alerts in the image are not addressable via npm and will be picked up separately:

    • git-lfs Go stdlib (5 CVEs) — needs the git-lfs binary in the Dockerfile bumped to a build that uses Go ≥1.25.10
    • Debian gnutls28 (4 CVEs) — upstream shows "not fixed" yet
    • Debian nghttp2 (1 CVE) — base image rebuild will pick it up on next bun:debian bump
    Downloads
  • Stable

    GiteaMirror released this 2026-05-15 23:10:48 -05:00 | 8 commits to main since this release

    📅 Originally published on GitHub: Sat, 16 May 2026 04:22:43 GMT
    🏷️ Git tag created: Sat, 16 May 2026 04:10:48 GMT

    What's new

    fix: org-owned repos visible again to sync, scheduler, and cleanup (#286)

    #283 dropped organization_member from the GitHub repo-listing affiliation filter. Repos owned by orgs the user belongs to became invisible to the main sync, the scheduler, and — worst of all — the orphan-cleanup pass, which would archive (or with CLEANUP_DELETE_IF_NOT_IN_GITHUB=true, delete) them on every restart.

    The affiliation filter now always includes organization_member, regardless of the INCLUDE_COLLABORATOR_REPOS toggle. The toggle's original semantics from #283 are preserved.

    fix: reconcile issue/PR/label/milestone metadata on every sync (#287)

    A one-shot guard added in #266 meant metadata only mirrored on the first sync of a repo. Edits made on GitHub afterwards — renamed issues, new labels, edited bodies — never propagated. This was a regression of #165, which #184 had already fixed via marker-based idempotent upserts.

    Reconciliation now runs every sync. The underlying mirror functions remain idempotent: issues match by [GH-ISSUE #N] markers, PRs by [PR #N], labels by name, milestones by title. Existing entries are PATCH'd in place — no duplicates.

    Note: slightly increases GitHub API usage per sync for repos with many issues/PRs. A since=lastSyncedAt optimization is planned as a follow-up.


    Thanks to @riguettodev for both fixes.

    Downloads
  • Stable

    GiteaMirror released this 2026-05-04 03:30:10 -05:00 | 11 commits to main since this release

    📅 Originally published on GitHub: Mon, 04 May 2026 08:30:39 GMT
    🏷️ Git tag created: Mon, 04 May 2026 08:30:10 GMT

    What's new

    feat: opt out of collaborator repos in GitHub imports (#283, closes #279)

    GitHub's authenticated repo listing returns every repo the user has access to by default — owner, collaborator, and organization member. For users who only want to mirror their own work, collaborator repos showed up as noise.

    This release adds an Include collaborator repositories toggle in the GitHub configuration panel. When unchecked, the import scopes the GitHub API affiliation filter to owner only, so collaborator-only repos are excluded.

    • Default: on. Existing users see no behavior change. Uncheck to opt out.
    • New env var INCLUDE_COLLABORATOR_REPOS (default true) for env-driven (Docker) deployments. Set to false to disable from the environment without touching the UI.
    • Cleanup safety net. When the toggle is off, the orphan-cleanup pass still asks GitHub for the full list (owner + collaborator), so previously-mirrored collaborator repos are not flagged as orphaned and archived/deleted. Toggling the option off only affects what gets imported, never what gets removed.
    • Round-trip and affiliation tests in src/lib/utils/config-mapper.test.ts and src/lib/github-affiliation.test.ts.

    This is the proper rewrite of #279, which was closed because the field had been added to the UI type only and never reached the runtime read site.

    Downloads
  • Stable

    GiteaMirror released this 2026-05-03 23:44:09 -05:00 | 13 commits to main since this release

    📅 Originally published on GitHub: Mon, 04 May 2026 04:44:30 GMT
    🏷️ Git tag created: Mon, 04 May 2026 04:44:09 GMT

    What's new

    feat: surface auto-mirror toggle in Automation settings (refs #278)

    Follow-up to v3.15.8. That release made scheduleConfig.autoMirror an independent trigger in the scheduler, but it could still only be enabled via the AUTO_MIRROR_REPOS env var. This release adds a UI toggle so the option is reachable from the Automation tab without touching the environment.

    • New checkbox "Auto-mirror new repositories" in Automation → Automatic Syncing
    • Visible only when scheduling is enabled (auto-mirror without a scheduler is meaningless)
    • Independent of the existing "Auto-mirror new starred repositories" toggle in GitHub settings — together they cover the full owned/starred matrix

    Together with v3.15.8, this completes the auto-mirror UX described in #278: new repos discovered on GitHub are now mirrored on the next scheduled sync without any manual click, and both owned and starred scopes are independently controllable from the UI.

    No schema or migration change.

    Downloads
  • Stable

    GiteaMirror released this 2026-05-03 22:42:57 -05:00 | 15 commits to main since this release

    📅 Originally published on GitHub: Mon, 04 May 2026 03:43:27 GMT
    🏷️ Git tag created: Mon, 04 May 2026 03:42:57 GMT

    What's new

    fix: make autoMirrorStarred actually trigger auto-mirror (fixes #278)

    The "Auto-mirror new starred repositories" checkbox in the GitHub settings was a filter layered on top of scheduleConfig.autoMirror, which itself is only settable via the AUTO_MIRROR_REPOS env var (no UI). So users who checked the box saw their starred repos auto-imported but never mirrored — contradicting the label.

    This release makes the two flags independent triggers in the scheduler:

    • autoMirror=true → auto-mirror owned (and self-starred) repos
    • autoMirrorStarred=true → auto-mirror repos starred from other owners
    • Either flag on its own enters the auto-mirror phase; the filter scopes the work accordingly

    Also normalized the owner comparison to lowercase since GitHub usernames are case-insensitive — previously a self-starred repo whose stored owner casing differed from githubConfig.owner would be misclassified as a third-party star and silently skipped.

    Behavior change to flag: anyone who currently has the starred checkbox on (broken state) will start getting starred repos mirrored after upgrading. Users with AUTO_MIRROR_REPOS=true see no change.

    autoMirror autoMirrorStarred Before After
    off off nothing nothing
    on off owned + self-starred owned + self-starred (unchanged)
    off on nothing (bug) third-party starred only
    on on everything everything (unchanged)

    A truth-table test in src/lib/scheduler-service.test.ts guards against re-introducing the bug.

    Note: this release fixes the starred half of #278. Auto-mirroring all owned repos still requires AUTO_MIRROR_REPOS=true at container start; surfacing that in the UI is the remaining tracked work on the issue.

    Downloads
  • Stable

    GiteaMirror released this 2026-05-03 21:50:26 -05:00 | 16 commits to main since this release

    📅 Originally published on GitHub: Mon, 04 May 2026 02:50:36 GMT
    🏷️ Git tag created: Mon, 04 May 2026 02:50:26 GMT

    What's new

    fix: unstick repos in 'mirroring' on transient errors (fixes #268)

    Repositories could get permanently stuck in the mirroring state — with no failure entry in the activity log — when a transient error hit during the Gitea migrate call. The catch block referenced let migrateSucceeded that had been declared inside the same try block; block-scoping made it invisible from catch, so the catch crashed with ReferenceError: migrateSucceeded is not defined before it could update the DB to failed.

    This release hoists the declaration above the try in both mirrorGithubRepoToGitea and mirrorGitHubRepoToGiteaOrg, restoring the intended behavior:

    • transient errors (timeouts, 5xx, etc.) now correctly transition the repo to failed instead of leaving it stuck in mirroring
    • mirroredLocation is cleared when the migrate call itself never succeeded
    • a failure entry is written to the activity log
    • the original error message is preserved on retry (no more misleading Failed to mirror repository: migrateSucceeded is not defined)

    Upgrade note: anyone who saw repos pile up in mirroring after upgrading from older versions can retry those repos after this release — they will now move to failed and become retriable instead of getting stuck again.

    A structural regression test in src/lib/gitea-mirror-failure-recovery.test.ts guards against re-introducing the scoping bug.

    See full discussion in #268.

    Downloads
  • Stable

    GiteaMirror released this 2026-04-26 03:13:51 -05:00 | 18 commits to main since this release

    📅 Originally published on GitHub: Sun, 26 Apr 2026 08:14:06 GMT
    🏷️ Git tag created: Sun, 26 Apr 2026 08:13:51 GMT

    What's new

    feat: warn when destination Forgejo has the known mirror-credential bug (refs #263)

    Forgejo versions before v15.0.0 silently discard auth_username/auth_password sent to /api/v1/repos/migrate, so subsequent pull-mirror sync of private repos fails with terminal prompts disabled. The bug was fixed upstream in Forgejo PR #11909 and the fix is only in v15.0.0+ — it was not backported to v12.x, v13.x, or v14.x.

    The Gitea config "Test Connection" flow now probes /api/v1/version, detects Forgejo via the +gitea- suffix, and shows a clear in-app warning when the connected server reports a Forgejo major version below 15. The warning links to the upstream PR and tells users exactly what to do (upgrade Forgejo, then delete + re-mirror affected repos).

    Pure Gitea servers and Forgejo v15.0.0+ are unaffected — no warning shown.

    See full discussion in #263.

    Downloads
  • Stable

    GiteaMirror released this 2026-04-22 08:51:13 -05:00 | 20 commits to main since this release

    📅 Originally published on GitHub: Wed, 22 Apr 2026 13:51:35 GMT
    🏷️ Git tag created: Wed, 22 Apr 2026 13:51:13 GMT

    What's Changed

    Follow-up to v3.15.4 — relaxes the dashboard config gate so users with tokens but no username don't get locked out.

    Fixed

    • Dashboard rendered all zeros for users whose config had empty username fields (#271). The useConfigStatus hook required githubConfig.username and giteaConfig.username to be non-empty before letting the dashboard fetch data. In practice neither is required at runtime:

      • The GitHub token is self-authenticating via listForAuthenticatedUser — no username needed.
      • The Gitea username isn't used under single-org or flat-user mirror strategies.

      Users who configured via env vars without setting GITHUB_USERNAME / GITEA_USERNAME (the form's required attribute is only client-side and the save endpoint doesn't enforce it either) ended up with empty strings in those fields. Mirroring kept running fine because tokens alone are sufficient — but the dashboard refused to fetch and rendered zeros.

      The gate now only requires what's actually needed at runtime: the GitHub token, and the Gitea URL + token. The githubOwner field is still exported for consumers that want to display an owner; only the gate is relaxed.

    Compatibility

    No schema changes, no migrations. Pure frontend hook change.

    Verification

    All 231 unit tests pass. bun run build succeeds.

    Full Changelog: https://github.com/RayLabsHQ/gitea-mirror/compare/v3.15.4...v3.15.5

    Downloads
  • Stable

    GiteaMirror released this 2026-04-21 21:41:17 -05:00 | 22 commits to main since this release

    📅 Originally published on GitHub: Wed, 22 Apr 2026 02:41:43 GMT
    🏷️ Git tag created: Wed, 22 Apr 2026 02:41:17 GMT

    What's Changed

    Bug fix release — dashboard no longer renders empty when a user accidentally has more than one configs row.

    Fixed

    • Dashboard showed zeros / "no repositories" while data was intact in the database (#271). Several SELECT … FROM configs WHERE userId = ? LIMIT 1 queries had no ORDER BY, so when a user's database accidentally contained more than one configs row for the same user (from an env-loader insert path or a partial default-config create), SQLite returned a non-deterministic row.

      In the reported case /api/config handed back an empty stub while /api/dashboard's repo and org counts came from the populated active row. The dashboard's useConfigStatus hook then saw missing username/token, treated config as incomplete, and never fetched dashboard data — the UI rendered with all zeros even though hundreds of repos were sitting in the database, mirroring fine in the background.

      Every "fetch the user's config" query now applies ORDER BY isActive DESC, updatedAt DESC before LIMIT 1, so the active and most-recently-updated row consistently wins. The env-config-loader's "first user" pick is now ordered by createdAt ASC for the same deterministic-across-restarts reason.

      Sites that already filter on isActive = true explicitly (cleanup service, scheduler, repositories/organizations/orgs-sync/cleanup-trigger endpoints) are unchanged.

    Compatibility

    No schema changes, no migrations. The fix is purely a query-level change: for the ~99% of installs that have a single config row, behavior is identical. For installs with duplicate config rows, the active populated row is now selected instead of a random one.

    Verification

    All 231 unit tests pass. bun run build succeeds.

    Full Changelog: https://github.com/RayLabsHQ/gitea-mirror/compare/v3.15.3...v3.15.4

    Downloads