-
v0.6.17 Stable
released this
2026-07-15 01:56:27 +00:00 | 47 commits to main since this releaseFixed
ForgejoRepository.spec.owneris now immutable, matching its siblingspec.nameand every
other identity field across the API. A repository's identity is(owner, name)— the reconciler
keysGetRepo/CreateOrgRepo/DeleteRepoon both — so editingownerin place would create a
new repo under the new owner and orphan the original in Forgejo (the finalizer only deletes the
new owner/name). The lifecycle-contract doc already declared owner part of the immutable identity;
this adds theself == oldSelfCEL validation that was missing on that one field. The migration
importSource.ownerstays mutable (it is a one-shot seed source, not the repo's identity).
Included changes (v0.6.16 -> v0.6.17)
1e24fc9588e5fix(repository): make spec.owner immutable (matches spec.name + closes an orphan foot-gun)
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.16 Stable
released this
2026-07-14 21:07:41 +00:00 | 51 commits to main since this releaseFixed
- Delete no longer leaks a remote resource (or its live credential) when the status ID was
never persisted. Six ID-keyed finalizer Delete handlers —ForgejoOAuthApp,ForgejoSSHKey,
ForgejoLabel,ForgejoRelease,ForgejoTagProtection,ForgejoTeam— no-op'd when their
Status.<X>ID == 0, so a CR deleted after the remote create landed but before its status write
persisted orphaned the resource in Forgejo forever. For an OAuth app that means a live client
secret, and for an SSH key a live public key, outliving the deprovisioned CR. Each Delete now
recovers the target ID via the same natural-key lookup its Converge already uses to adopt an
existing resource (OAuth app by name, SSH key by username+title, label/tag-protection by
name/pattern, release by tag, team by org+name) before deleting. The OAuth-app fallback deletes
every same-name app it owns, matching Converge's duplicate-pruning model. - Finalizer Delete is now idempotent on a 404. All six handlers (plus the shared
is404helper)
treat an already-absent remote resource as a completed delete, so a benign race — deleted out of
band, or a retried finalizer after the first delete landed — no longer surfaces a spurious error.
The four parent-scoped fallback lookups (label/tag-protection by repo, SSH key by user, team by
org) also tolerate a 404 on the list itself: when the parent repo/user/org was deleted (tenant
teardown cascade), the child is already gone, so Delete cleanly no-ops instead of erroring. A
non-404 list failure (transient 5xx) still surfaces. (forgejodelete_leak_test.go:
recovers-ID-when-status-empty, idempotent-404, parent-gone, and non-404-propagates coverage.)
Included changes (v0.6.15 -> v0.6.16)
ec47ea8d9b31fix(delete): recover remote id via natural key so a status-lost CR can't leak
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Delete no longer leaks a remote resource (or its live credential) when the status ID was
-
v0.6.15 Stable
released this
2026-07-14 17:22:43 +00:00 | 55 commits to main since this releaseChanged
- Incremental release.
Included changes (v0.6.14 -> v0.6.15)
829cbc165461fix(forgejo): 3 credential/reconcile bugs (password loss, team pagination, webhook secret rotation)
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.14 Stable
released this
2026-07-13 18:51:57 +00:00 | 59 commits to main since this releaseFixed
- Bump
libseanfarm-operatorv0.4.1 → v0.4.7. Picks up six releases of shared reconcile-
harness fixes + test coverage the operator was missing, notably the v0.4.4 fix that stops the
harness stampingObservedGenerationon a Converge error underObservedGenOnConvergedOnly.
Build + full envtest controller suite green on v0.4.7.
Included changes (v0.6.13 -> v0.6.14)
8652fd08c969fix(deps): bump libseanfarm-operator v0.4.1 -> v0.4.7 (blocker: ObservedGen-stamp-on-error)
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Bump
-
v0.6.13 Stable
released this
2026-07-09 06:44:18 +00:00 | 63 commits to main since this releaseChanged
- Incremental release.
Included changes (v0.6.12 -> v0.6.13)
51cad7e65ad4test: green the controller suite so CI can gate on it
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.12 Stable
released this
2026-07-09 00:56:38 +00:00 | 68 commits to main since this releaseChanged
- Incremental release.
Included changes (v0.6.11 -> v0.6.12)
d53e90cb8477docs(crd): lifecycle contracts across the forgejo CRDs (kubectl explain)ce2a4da47cc1docs(collaborator): surface the lifecycle contract in the CRD (kubectl explain)
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.11 Stable
released this
2026-07-07 19:36:41 +00:00 | 75 commits to main since this releaseChanged
ForgejoTagProtection+ForgejoCollaborator: skip the write when already in
sync, so steady-state reconciles no longer edit/re-grant every requeue. Tag
protection compares the live whitelist (order-insensitive) before
EditTagProtection; the collaborator grant is skipped when the user is already
a direct collaborator (IsCollaborator) at the desired permission
(CollaboratorPermission, with owner→admin coercion) — gated on direct
membership so an effective-permission match (repo owner, org admin, or
public-repo reader) never skips a genuinely-needed grant. This completes the
drift-skip audit: the other 10 controllers already diff-gate their writes.- Cut steady-state Forgejo API load. The gitea client — and its construction-time
GET /api/v1/versionprobe — is now cached per endpoint instead of rebuilt on
every reconcile of every resource, so the version is probed once per credential
rather than once per reconcile (~halving API calls); all clients share one
connection-pooledhttp.Transportwith a larger per-host idle pool. The default
drift-resync interval is raised from 5m to 15m — Forgejo has no watch/event API
for the settings these controllers manage, so periodic resync is the only drift
signal, and since the operator is the writer, drift is rare. - Reconcile + client timings are now configurable (defaults unchanged in spirit)
via flags that govern all controllers uniformly through the shared harness:
--resync-interval,--progressing-interval,--transient-interval,
--forgejo-client-timeout,--max-concurrent-reconciles,--retry-base-delay,
--retry-max-delay. Previously these were hardcoded.
Included changes (v0.6.10 -> v0.6.11)
c547128af5e6Merge branch 'trunk' of https://code.sean.farm/sean/forgejo-operator into feat/driftskip-tag-collaborator9868082c185aperf(controllers): drift-skip the last two unconditional writers17020fcfe0eeMerge branch 'trunk' of https://code.sean.farm/sean/forgejo-operator into feat/reduce-forgejo-polling34ff7e7b7b23perf(client): cache Forgejo client + configurable reconcile timings
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.10 Stable
released this
2026-07-07 18:55:05 +00:00 | 84 commits to main since this releaseFixed
ForgejoBranchProtection: address the rule by its rule name, not the branch
name, on the check/edit path. Forgejo keysbranch_protections/{name}on
rule_name(which only defaults to the branch name at create time), so a CR
whosespec.ruleNamediffered fromspec.branchNamere-checked by branch name,
404'd, re-created, and Forgejo 409'd — the resource never converged and hammered
Forgejo every requeue. Resolve the rule name once (status →spec.ruleName→
branch) and key GET/EDIT/DELETE on it consistently.ForgejoBranchProtection:Deletenow derives the rule name from spec when
status.ruleNameis unset (a created-but-status-lost rule is cleaned up instead
of orphaned), and treats a delete 404 as success (idempotent finalizer).ForgejoBranchProtection: skip the editPATCHwhen the live rule already
matches every managed field, cutting steady-state write load to Forgejo.
Added
- First handler-level unit tests against a fake Forgejo (
httptest) — create,
edit, rule-name idempotency, in-sync skip, error propagation, and delete
(by-rule-name, idempotent 404, derive-from-spec, no-op) for
ForgejoBranchProtection. ForgejoTokenCRD + controller: declaratively mint and rotate a Forgejo
personal access token into a Secret. The controller authenticates as
spec.usernamevia HTTP Basic auth using the password inspec.authSecretRef
(Forgejo'sPOST /users/{user}/tokensaccepts BasicAuth only — a token cannot
mint a token), mints a uniquely-named scoped PAT, writes it tospec.output,
and revokes the previous one (mint-before-revoke → no credential gap). Rotation
is controller-enforced onspec.rotateEvery(default 168h) because Forgejo 14
PATs carry no server-side expiry; it also re-mints whenever the active token
is missing server-side (e.g. after a Forgejo migration wipes tokens), so the
credential self-heals instead of silently going stale — replacing the one-shot,
never-rotating*-token-issuerJobs. Owns tokens by name prefix (<base>/
<base>-<n>), prunes stragglers, and revokes on delete. Purpose-built to retire
the fragileforgejo-admin-token/forgejo-pipeline-bot-tokenissuers.
Included changes (v0.6.9 -> v0.6.10)
729bd6adede9feat(forgejotoken): CRD + controller to mint & rotate Forgejo PATsf16707ea1701fix(branchprotection): key rule ops by rule name, not branch name
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.9 Stable
released this
2026-07-06 22:28:00 +00:00 | 91 commits to main since this releaseAdded
ForgejoTagProtectionCRD + controller: declaratively manage a repo's
tag-protection rules (globnamePattern+whitelistUsernames/whitelistTeams)
through the gitea SDK'stag_protectionsAPI. Because the API has no get-by-name
and keys rules by int64 ID, Converge lists (paginated), matches on the natural
namePatternkey, create-or-edits, and storesstatus.tagProtectionIDfor
edit/delete — mirroringForgejoLabel. Lets tag creation (e.g. releasev*tags)
be restricted to the in-cluster pipeline identity.ForgejoCollaboratorCRD + controller: declaratively grant a user direct
collaborator access (read/write/admin) on a single repository via
AddCollaborator(idempotent PUT), removing it on delete. This is the only way to
grant write on a user-owned repo (sean/*) —ForgejoTeamonly covers
org-owned repos — so a dedicated non-adminpipeline-botcan be given write on
each pipeline repo without the site-admin token.ForgejoBranchProtection: merge-whitelist fields (enableMergeWhitelist,
mergeWhitelistUsernames,mergeWhitelistTeams). With push disabled, protected
branches advance only via PR merges; enabling this + listingpipeline-botforces
every change to a protected branch through the pipeline (no human or bot outside
the whitelist can merge).
Included changes (v0.6.8 -> v0.6.9)
4b1c1ef9e473feat(crd): ForgejoTagProtection + ForgejoCollaborator + merge-whitelistc0152458da61fix(cicd): auto-resolve CHANGELOG land conflicts via .gitattributes merge=union16b1f5d488f5fix(ci): pin golang:1.26 builder base by digesta6ab3a1ab9cachore: retrigger CI (transient buildkit lease error)8c50685f4aa8docs(forgejorepository): correct stale cloneAddrFor comment (no server derivation)
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.6.8 Stable
released this
2026-07-03 22:53:36 +00:00 | 103 commits to main since this releaseAdded
- Unit tests for the import-source helpers
cloneAddrFor/serviceTypeFor:
cover theType→CloneAddrandType→GitServiceTypemappings,
including the gitea-default and plain-git fallback paths.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Unit tests for the import-source helpers