488b403863dc439b5e9dfa0a8325bdfe886dd3a3
braney
  Tue Aug 4 06:51:42 2026 -0700
hgConfCatalog: register login.emailLink, login.oauth.providers and the per-provider oauth family, refs #37925

The hgLogin email-link and social sign-in work added three hg.conf reads with no
catalog rows, which is what --reconcile was failing on.  login.emailLink is filed
as a mirror knob with the gate argument recorded in debatable=; the per-provider
settings are built with safef, so they are catalogued as a runtime name.

diff --git src/hg/utils/hgConfCatalog/hgConfCatalog.py src/hg/utils/hgConfCatalog/hgConfCatalog.py
index 982d0e5fa16..60390366908 100755
--- src/hg/utils/hgConfCatalog/hgConfCatalog.py
+++ src/hg/utils/hgConfCatalog/hgConfCatalog.py
@@ -446,30 +446,42 @@
           role="knob", public=True, verified=True,
           note="Take identity from HTTP basic auth rather than the login "
                "system."),
         h("login.relativeLink", "flag", "hg/lib/hdb.c:3650", default="FALSE",
           role="knob", public=True, verified=True,
           note="Relative rather than absolute login links."),
         h("login.acceptAnyId", "flag", "hg/lib/wikiLink.c:248",
           default="FALSE", role="knob", verified=True,
           note="Accept any identity token.  Development only, and dangerous "
                "on a public machine."),
         h("login.acceptIdx", "flag", "hg/lib/wikiLink.c:255", default="FALSE",
           role="knob", verified=True, note="Companion to login.acceptAnyId."),
         h("login.pwdEyeIcon", "flag", "hg/hgLogin/hgLogin.c:1429",
           default="TRUE", role="knob", verified=True,
           note="Show-password eye icon on the login form."),
+        h("login.emailLink", "flag", "hg/hgLogin/hgLogin.c:1563",
+          default="FALSE", role="knob", public=True, verified=True,
+          ticket="37929",
+          note="Passwordless sign-in: the user is emailed a one-time link "
+               "instead of typing a password.  The same switch shows the "
+               "change-email page, since that page has no password check "
+               "either.  It needs working outbound mail, so a mirror without "
+               "it leaves this off permanently.",
+          debatable="Filed as a knob because outbound mail is a property of "
+                    "the machine, not of the release.  It is a gate if the "
+                    "plan is to flip the default TRUE once the flow is "
+                    "proven on the RR, in which case it needs a sunset."),
         h("analytics.trackClicks", "flag", "hg/lib/googleAnalytics.c:63",
           default="TRUE", role="knob", verified=True,
           note="Report link clicks to analytics.  A mirror with its own "
                "privacy policy turns this off."),
         h("analytics.trackButtons", "flag", "hg/lib/googleAnalytics.c:64",
           default="TRUE", role="knob", verified=True,
           note="Report button presses to analytics."),
         h("wikiTrack.readOnly", "flag", "hg/lib/wikiTrack.c:292",
           default="FALSE", role="knob", verified=True, deprecated=True,
           note="Make the wiki annotation track read-only.  The wiki track "
                "itself is effectively retired."),
         h("cdw.siteIsPublic", "flag",
           "hg/cirm/cdw/cdwGetFile/cdwGetFile.c:62", default="FALSE",
           role="knob", verified=True, deprecated=True,
           note="CIRM data warehouse is public.  Belongs to the cirm CGIs, "
@@ -993,30 +1005,38 @@
         h("login.systemName", "internal", "hg/lib/wikiLink.c:31", public=True,
           verified=True, family="login"),
         h("login.browserName", "internal", "hg/hgLogin/hgLogin.c:67",
           public=True, verified=True, family="login"),
         h("login.browserAddr", "url", "hg/hgLogin/hgLogin.c:76", public=True,
           verified=True, family="login"),
         h("login.mailSignature", "internal", "hg/hgLogin/hgLogin.c:85",
           public=True, verified=True, family="login"),
         h("login.mailReturnAddr", "email", "hg/hgLogin/hgLogin.c:96",
           public=True, verified=True, family="login"),
         h("login.approvedReturn", "url", "hg/hgLogin/hgLogin.c:326",
           default="NULL", verified=True, family="login"),
         h("login.cookieSalt", "credential",
           "hg/hgPhyloPlace/hgPhyloPlace.c:581", public=True, verified=True,
           family="login", note="Salt for the login cookie.  A secret."),
+        h("login.oauth.providers", "internal",
+          "hg/hgLogin/oauthLogin.c:127", public=True, verified=True,
+          family="login", ticket="37984",
+          note="Comma-separated list of social sign-in providers to offer.  "
+               "Each name listed here is then configured through its own "
+               "login.oauth.<name>.* settings, none of which appear as "
+               "literals in the tree; see {key}.  google, orcid and github "
+               "are picked up even when unlisted, if they carry a clientId."),
         h("wiki.host", "url", "hg/lib/wikiLink.c:199", public=True,
           verified=True, family="wiki", deprecated=True),
         h("wiki.userNameCookie", "internal", "hg/lib/wikiLink.c:50",
           default='"hgLoginUserName"', public=True, verified=True,
           family="wiki"),
         h("wiki.loggedInCookie", "internal", "hg/lib/wikiLink.c:51",
           default='"hgLoginIdKey"', public=True, verified=True, family="wiki"),
         h("wiki.sessionCookie", "internal", "hg/lib/wikiTrack.c:342",
           public=True, verified=True, family="wiki", deprecated=True),
         h("wikiTrack.URL", "url", "hg/hgGene/wikiTrack.c:38", default="NULL",
           public=True, verified=True, family="wikiTrack", deprecated=True),
         h("wikiTrack.browser", "internal", "hg/hgGene/wikiTrack.c:297",
           default="DEFAULT_BROWSER", public=True, verified=True,
           family="wikiTrack", deprecated=True),
         h("wikiTrack.dbList", "internal", "hg/lib/wikiTrack.c:318",
@@ -1200,30 +1220,39 @@
             "silently ignored.",
     "vars": [
         h("{themeKey}", "internal", "hg/lib/cart.c:3006", verified=True,
           note="browser.theme.<name>, resolved from the theme the user "
                "picked."),
         h("{cfgName}", "internal", "hg/hgTracks/hgTracks.c:8894",
           verified=True),
         h("{confName}", "internal", "hg/lib/hdb.c:5447", verified=True,
           note="Resolves to db.grp, passed in by loadGrps()'s only caller at "
                "hdb.c:5479.  Catalogued under its real name as well."),
         h("{confVariable}", "internal", "hg/hgTracks/quickLift.c:26",
           verified=True, ticket="37788",
           note="quickLift colour settings, named per use."),
         h("{overlapKey}", "internal", "hg/hgc/myVariantsClick.c:579",
           verified=True, note="Goes with the doMyVariants gate."),
+        h("{key}", "internal", "hg/hgLogin/oauthLogin.c:44", verified=True,
+          ticket="37984",
+          note="login.oauth.<provider>.<field>, built with safef from the "
+               "provider names in login.oauth.providers, so the whole family "
+               "is invisible to any scan.  The fields are clientId, "
+               "clientSecret, label, type, issuer, authUrl, tokenUrl, "
+               "userinfoUrl and scopes.  A second read tries the older "
+               "login.<provider>.<field> spelling, which is why a mirror can "
+               "have credentials under either prefix."),
         h("{temp}", "internal", "hg/hgcentralTidy/hgcentralTidy.c:80",
           verified=True),
         h("{cdwSetting}", "internal",
           "hg/cirm/cdw/cdwWebBrowse/cdwWebBrowse.c:341", verified=True,
           deprecated=True),
     ],
 }
 
 
 # ---------------------------------------------------------------------------
 # assembly
 # ---------------------------------------------------------------------------
 
 SECTIONS = [
     ("Release gates", RELEASE_GATES),