feat(oidc): rename the auth source Gitborg Auth -> Bitborg Auth #383

Sammanfogat
supernaut sammanfogade 1 incheckning från feat/rename-oidc-source-name in i main 2026-08-05 18:15:35 +00:00
Ägare

Step C of the OIDC auth-source rename Gitborg Auth → Bitborg Auth — the last user-visible
gitborg string on the service, since the source name is also the login-button label and the
callback slug /user/oauth2/<name>/callback.

What this changes

  • forgejo_oidc_source_name → Bitborg Auth. Kanidm's callback + landing URL and Caddy's
    @forgejo_login_page redirect all derive from it, so they move with it.
  • Drops the transitional second callback from the Kanidm forgejo client, returning it to a single
    origin_urls entry.
  • Grafana's GF_AUTH_GENERIC_OAUTH_NAME — a separate hardcoded literal that does not derive
    from the variable, so the Forgejo rename alone would have left Grafana's sign-in page reading the
    old name.
  • Runbook: records the rename, replaces the old "two-source cleanup" note with the sequenced
    zero-gap procedure, and corrects two notes that have since gone stale.

Why it is sequenced

The name lives in two systems at once, so whichever side moves first breaks logins: rename Forgejo
and it posts a callback Kanidm has not registered; move Kanidm and it stops accepting the callback
Forgejo still posts. Order used: register both callbacks and apply kanidm → rename the live source
in place and restart Forgejo → this PR.

No secret rotation. login_source.id is unchanged and users link to a source by ID, not by name, so
existing OIDC links survive untouched.

Two findings worth recording

The canonical sign-in URL was serving 500 between steps B and C. GET /user/login → 302 to the
old slug → 500. Step B had verified /user/oauth2/<new name> — the route it changed — but not the
Caddy redirect a user actually traverses. No blackbox probe covers /user/login, so all six probes
reported 1 throughout. This PR is the fix.

--check cannot prove the add-source guard is safe. List existing Forgejo auth sources is a
command, so it is skipped under --check; the guard then evaluates <name> not in '' (true), and
the add-source task reports skipping regardless because it is also a command. The valid proof is
a differential against the live host:

request result
/user/oauth2/Bitborg%20Auth 307 → Kanidm, new callback
/user/oauth2/Gitborg%20Auth 500
/user/oauth2/Definitely%20Not%20A%20Source 500 (negative control)

The old name behaving identically to a name that was never registered is what establishes that
exactly one source exists and it carries the new name — so the real-run guard evaluates false and
cannot duplicate.

Dry-run

site.yml --check --diff: prod changed=5 failed=0, monitoring changed=2 failed=0. The five are
the kanidm provisioning state, the app.ini render + its flush_handlers, and the Caddyfile render

  • Caddy restart; monitoring is grafana.container + its restart. Expect brief Forgejo, Caddy and
    Grafana restarts.

ansible-lint was not run in this session (blocked locally); --syntax-check, markdownlint and
prettier all pass.

Verification after apply

curl -sS -o /dev/null -D - https://git.bitborg.se/user/login | grep -iE '^HTTP/|^location'
# expect: 302 -> /user/oauth2/Bitborg%20Auth  (then 307 to Kanidm, NOT 500)
forgejo admin auth list   # exactly one source, id 2

Plus a real browser sign-in, which is the only end-to-end proof.

Step C of the OIDC auth-source rename `Gitborg Auth` → `Bitborg Auth` — the last user-visible `gitborg` string on the service, since the source name is also the login-button label and the callback slug `/user/oauth2/<name>/callback`. ## What this changes - `forgejo_oidc_source_name` → `Bitborg Auth`. Kanidm's callback + landing URL and Caddy's `@forgejo_login_page` redirect all derive from it, so they move with it. - Drops the transitional second callback from the Kanidm `forgejo` client, returning it to a single `origin_urls` entry. - Grafana's `GF_AUTH_GENERIC_OAUTH_NAME` — a **separate** hardcoded literal that does not derive from the variable, so the Forgejo rename alone would have left Grafana's sign-in page reading the old name. - Runbook: records the rename, replaces the old "two-source cleanup" note with the sequenced zero-gap procedure, and corrects two notes that have since gone stale. ## Why it is sequenced The name lives in two systems at once, so whichever side moves first breaks logins: rename Forgejo and it posts a callback Kanidm has not registered; move Kanidm and it stops accepting the callback Forgejo still posts. Order used: register both callbacks and apply `kanidm` → rename the live source **in place** and restart Forgejo → this PR. No secret rotation. `login_source.id` is unchanged and users link to a source by ID, not by name, so existing OIDC links survive untouched. ## Two findings worth recording **The canonical sign-in URL was serving 500 between steps B and C.** `GET /user/login` → 302 to the old slug → 500. Step B had verified `/user/oauth2/<new name>` — the route it changed — but not the Caddy redirect a user actually traverses. No blackbox probe covers `/user/login`, so all six probes reported `1` throughout. This PR is the fix. **`--check` cannot prove the add-source guard is safe.** `List existing Forgejo auth sources` is a `command`, so it is skipped under `--check`; the guard then evaluates `<name> not in ''` (true), and the add-source task reports `skipping` regardless because it is also a `command`. The valid proof is a differential against the live host: | request | result | | ------------------------------------------- | --------------------------------------- | | `/user/oauth2/Bitborg%20Auth` | **307** → Kanidm, new callback | | `/user/oauth2/Gitborg%20Auth` | **500** | | `/user/oauth2/Definitely%20Not%20A%20Source` | **500** (negative control) | The old name behaving identically to a name that was never registered is what establishes that exactly one source exists and it carries the new name — so the real-run guard evaluates false and cannot duplicate. ## Dry-run `site.yml --check --diff`: prod `changed=5 failed=0`, monitoring `changed=2 failed=0`. The five are the kanidm provisioning state, the `app.ini` render + its `flush_handlers`, and the Caddyfile render + Caddy restart; monitoring is `grafana.container` + its restart. Expect brief Forgejo, Caddy and Grafana restarts. `ansible-lint` was not run in this session (blocked locally); `--syntax-check`, `markdownlint` and `prettier` all pass. ## Verification after apply ```bash curl -sS -o /dev/null -D - https://git.bitborg.se/user/login | grep -iE '^HTTP/|^location' # expect: 302 -> /user/oauth2/Bitborg%20Auth (then 307 to Kanidm, NOT 500) forgejo admin auth list # exactly one source, id 2 ``` Plus a real browser sign-in, which is the only end-to-end proof.
supernaut lade till 1 incheckning 2026-08-05 18:12:50 +00:00
feat(oidc): rename the auth source Gitborg Auth -> Bitborg Auth
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m31s
b1a916d4b0
The last user-visible `gitborg` string on the service: the source name is also the
login-button label ("Sign in with <name>") and the callback slug
(/user/oauth2/<name>/callback).

Renamed with NO login gap, in three steps, because the name lives in two systems at
once and whichever side moves first breaks logins — rename Forgejo and it posts a
callback Kanidm has not registered; move Kanidm and it stops accepting the callback
Forgejo still posts:

  A. register BOTH callbacks on the Kanidm forgejo client, apply kanidm only
  B. rename the live source IN PLACE (`admin auth update-oauth --id 2 --name`) and
     restart Forgejo — the in-memory OIDC provider does not pick the name up
     otherwise, the same way it does not pick up a changed secret
  C. move forgejo_oidc_source_name, drop the transitional callback, apply

This commit is step C.

No secret rotation, contrary to the plan's "the origin, the source name and the client
secret must move together". `login_source.id` is unchanged and users link to a source by
ID, not by name, so existing OIDC links survive untouched. That coupling only exists if
the source is deleted and re-added — which `auth delete` refuses anyway for a source
with linked users.

Ansible only ADDS a source whose name is absent, so the variable change and the live
rename must land together: a changed variable against an unchanged server produces a
SECOND source rather than a rename.

Two things step C turned out to be load-bearing for, neither of which was anticipated:

* Caddy's @forgejo_login_page redirect derives from the same variable, so between B and
  C the canonical https://git.bitborg.se/user/login served a 302 to the OLD slug and
  then a 500. Step B had verified /user/oauth2/<new name> directly — the route it had
  just changed — but not the redirect a user actually traverses. No blackbox probe
  covers /user/login, so all six kept reporting 1 throughout. Step C is the fix.

* The dry-run CANNOT prove the add-source guard is safe, so the reference check-run's
  "the add-source task is absent from the changed list" was not evidence. `List existing
  Forgejo auth sources` is a `command`, skipped under --check, so the guard evaluates
  `<name> not in ''` — true — and the add-source task then reports `skipping` whether
  the guard passed or failed, because it is also a `command`. The real proof is a
  differential against production: the new name 307s to Kanidm while the old name AND a
  deliberately bogus name both 500 identically, which establishes that exactly one
  source exists and it carries the new name.

Also renames Grafana's GF_AUTH_GENERIC_OAUTH_NAME, which is a SEPARATE hardcoded literal
and does not derive from forgejo_oidc_source_name — renaming the Forgejo source alone
would have left Grafana's sign-in page still reading "Gitborg Auth". Same class of miss
as the hardcoded KANIDM_HOST and the Forgejo footer link text. Its whole KEY=value stays
double-quoted, because systemd Environment= splits unquoted values on whitespace and the
value contains a space.

Runbook: records the rename, replaces the old "two-source cleanup" note with the
sequenced zero-gap procedure that was actually proven, and drops the claim that the
secret must move with the name. Corrects two notes that were true when written and are
not now: `fj pr create` works again on 0.6.0 (the browser workaround is unnecessary),
and the second fj credential store does NOT hold a separate server-side token — all
three key files held the same value, so revoking it as advised would have broken the
working CLI.
supernaut sammanfogade incheckning 132fed56fb till main 2026-08-05 18:15:35 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra!383
Ingen beskrivning angiven.