14ecff0730596f8be147b255afc8acb99e9095e2 max Fri Sep 18 09:06:06 2026 -0700 hgHubConnect: an api key made on one geo mirror now works on all of them, behind syncHubApiKeys #Preview2 week - bugs introduced now will need a build patch to fix #Preview2 week - bugs introduced now will need a build patch to fix Api keys live in the hgcentral of whichever mirror issued them, so a key made on genome.ucsc.edu was rejected on genome-euro and genome-asia, and the botDelay error told the user to go and make a second one. hgHubConnect now tells the other nodes about a key as soon as it generates or revokes one: cjGenerateApiKey and cjRevokeApiKey call syncApiKeyToOtherNodes(), which posts a hgHubSyncApiKey cartJson request to each peer, and cjSyncApiKey() on the far side writes it into that mirror's own table. The peers come from hgcentral.gbNode via the new geoMirrorNotifyOtherNodes(), and the request is signed with login.cookieSalt, which all of a site's mirrors already share - it is what makes the login cookie verifiable on each of them. So neither a list of mirror addresses nor a new shared secret needs provisioning. The notify is best effort: a peer that is down is warn()ed about and skipped, never failing the local generate or revoke, which has already committed by then. All of it is off unless hg.conf says syncHubApiKeys=on. With the gate off the sender returns at once, the receiver refuses the request outright rather than merely being unreachable, and botDelay keeps printing the old server-specific wording, which off is still the truth. Registered in hgConfCatalog.py as a gate, to be flipped once this is released. refs #38323 diff --git src/hg/inc/geoMirror.h src/hg/inc/geoMirror.h index cef76495c2c..63526f1c552 100644 --- src/hg/inc/geoMirror.h +++ src/hg/inc/geoMirror.h @@ -18,22 +18,31 @@ /* Return 2 letter country code for given IP. user has already checked table geoIpCountry6 exists. * Return error string otherwise. Free the response string. */ int geoMirrorDefaultNode(struct sqlConnection *centralConn, char *ipStr); // return default node for given IP struct slPair *geoMirrorThisNode(); /* Return this node (browser.node) as a single pair of name=shortLabel, val=domain, or NULL when * geo mirroring is off or gbNode has no row for it. slPairFreeValsAndList when done. */ struct slPair *geoMirrorOtherNodes(); /* Return the other geo mirror nodes, as pairs of name=shortLabel, val=domain, ordered by node. * The node this CGI is running on (browser.node) is left out. Returns NULL when geo mirroring * is off or this is the only node. slPairFreeValsAndList when done. */ +void geoMirrorNotifyOtherNodes(char *cgiName, struct slPair *cgiVars); +/* Best-effort: fire cgiVars (name=value) as a GET request at cgiName on every other geo mirror + * node (per geoMirrorOtherNodes()). No-ops if geo mirroring is off or this is the only node. + * Adds no authentication of its own -- callers must put their own signed proof into cgiVars, + * since the receiving CGI runs with no session/cart tying the request to a user. A slow or + * unreachable peer is logged with warn() and skipped; the caller's own action must already be + * complete locally before this is called, since a peer being down must never fail the local + * action. */ + char *geoMirrorMenu(); /* Create customized geoMirror menu string for substitution of into * in htdocs/inc/globalNavBar.inc * Reads hgcentral geo tables and hg.conf settings. * Free the returned string when done. */ #endif /* GEOMIRROR_H */