Concepts
The few ideas behind the operator, and the words the rest of the docs use.
How it works
you / GitOps ──apply──▶ Kubernetes API ──watch──▶ weebo-forgejo ──REST API──▶ Forgejo
(custom resources) (operator) (admin token)
▲ │
└──── status, events ────┘
└──▶ Secrets / VaultYou describe what Forgejo should contain as Kubernetes resources. The
operator watches them, compares each one with Forgejo, sends only the
changes needed, and writes the outcome back on the resource's status.
Credentials it generates are written to Secrets or Vault.
Vocabulary
| Term | Meaning |
|---|---|
| CR (custom resource) | One YAML object of a kind this operator adds, such as a ForgejoRepository. Each CR stands for one object in Forgejo. |
| CRD | The definition of a kind (its fields and their types). The chart installs them; see the CRD reference. |
| Reconcile | One pass where the operator compares a CR with Forgejo and fixes the difference. It runs when the CR changes, when something it refers to changes, and periodically. |
| Drift | A difference that appeared in Forgejo after the fact, such as a setting changed by hand in the UI. The next reconcile undoes it. |
| Authoritative | A field or list the operator enforces completely: for memberRefs on a team, anyone not listed is removed. |
Ref (organizationRef, userRef…) | A pointer to another CR by its Kubernetes name — of the same namespace, or of another one (namespace) when the operator allows it and the target shares itself — or to a Forgejo object no CR manages, by its Forgejo name (remoteName). |
| Management policy | Manage (the default) lets the operator create and edit the object. Observe only looks it up so other CRs can refer to it, without ever changing it. |
| Deletion policy | What happens in Forgejo when the CR is deleted: Orphan keeps the object, Delete removes it. |
| Finalizer | A marker Kubernetes keeps on a CR until the operator has finished cleaning up, so a deletion is never half done. |
| Secret targets | Where a generated credential is written: one or more Kubernetes Secrets and/or Vault paths. See Credentials. |
| Admission webhook | A check the API server runs before accepting a CR. It enforces the allow-list at kubectl apply time. |
| Disruptive update | A change Forgejo can only do by recreating the object, or one that breaks its consumers. It's refused unless you opt in with an annotation; see Disruptive changes. |
The kinds
Only the instance and the allow-list are cluster-scoped, governed by
Kubernetes RBAC alone. Every other kind is namespaced: it belongs to a
team, and — when bound to a shared ForgejoInstance — is also governed by
the allow-list. Every kind has a short name for
kubectl get.
| Kind | Short name | Scope | Stands for |
|---|---|---|---|
ForgejoInstance | fji | Cluster | The connection to a Forgejo |
ForgejoLocalInstance | fjli | Namespaced | A namespace's own connection to a Forgejo |
ForgejoUser | fjuser | Namespaced | A user or bot account |
ForgejoUserKey | fjukey | Namespaced | An SSH key on a user |
ForgejoOrganization | fjorg | Namespaced | An organization |
ForgejoTeam | fjteam | Namespaced | A team in an organization, and its members |
ForgejoNamespacePolicy | fjnp | Cluster | Allow-list rules for the namespaced kinds |
ForgejoRepository | fjrepo | Namespaced | A repository, its settings, team access and branch protection |
ForgejoWebhook | fjhook | Namespaced | A repository or organization webhook |
ForgejoDeployKey | fjdkey | Namespaced | An SSH deploy key on a repository |
ForgejoOAuth2Application | fjoauth | Namespaced | An OAuth2 client, delivered to a Secret |
ForgejoAccessToken | fjtoken | Namespaced | An API token, delivered to a Secret |
Status
Every CR reports the same way: a Ready condition with a reason (a
stable code such as Reconciled or NamespaceNotAllowed) and a readable
message, plus the Forgejo id of the object it owns. kubectl get shows
READY for every kind; kubectl describe shows the reason. All reasons are
listed in Reason codes.
Which Forgejo?
Every CR has an optional instanceRef ({name: main}). Leave it out when
the cluster has a single ForgejoInstance, which is used by default. With
several instances, set it on every CR. A namespace can also bring its own
server as a ForgejoLocalInstance. Once a CR is bound to an instance
(status.instance), it never moves to another one.