be590a4f6b10055e567a9ac717919cd99481272a
max
  Fri Sep 4 17:01:05 2026 -0700
Let a dataVersion file under /gbdb be read for hub tracks

A track may point dataVersion at a local file, and otto jobs use that to show
a live version string. Hub tracks were excluded, because a hub is supplied by
the user and could otherwise name any file on the server.

That also excludes the curated-hub assemblies. hs1 is served to the browser as
a hub, so its tracks are hub tracks, and hgTrackUi printed the raw path where
the version should be. Paths under /gbdb are safe to make an exception for:
that tree is public data, mirrored on hgdownload, so reading one discloses
nothing that is not already downloadable.

Also resolves $D against the plain database name, so it does not expand to
hub_NNNNN_hs1 on a curated hub.

refs #38268

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 51caa008e9b..134c01e9acc 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -10806,32 +10806,38 @@
 {
 // try the metadata
 metadataForTable(database, tdb, NULL);
 char *version = (char *)metadataFindValue(tdb, "dataVersion");
 
 // try trackDb itself, this automatically will go up the hierarchy
 if (version == NULL)
     version = trackDbSetting(tdb, "dataVersion");
 
 if (version != NULL && startsWith("/", version))
     {
     // dataVersion can also be the path to a local file, for otto tracks.
     // For quickLifted tracks the file lives on the source assembly, so
     // substitute $D using quickLiftDb rather than the destination database.
     char *liftDb = trackDbSetting(tdb, "quickLiftDb");
-    char *resolveDb = liftDb ? liftDb : database;
-    if (liftDb != NULL ||
+    char *resolveDb = trackHubSkipHubName(liftDb ? liftDb : database);
+    // A hub is user-supplied, so a hub track may not name just any local file.
+    // Paths under /gbdb are the exception: that tree is public data, mirrored on
+    // hgdownload, so reading one discloses nothing.  Curated-hub assemblies need
+    // this - hs1 and friends are served to the browser as a hub, which makes their
+    // otto tracks hub tracks, and without it hgTrackUi prints the raw path where
+    // the version should be.
+    if (liftDb != NULL || startsWith("/gbdb/", version) ||
         (!trackHubDatabase(database) && !isHubTrack(tdb->table)))
         {
         char *path = replaceInUrl(version, "", NULL, resolveDb, "", 0, 0, tdb->track, FALSE, NULL);
         struct lineFile* lf = lineFileMayOpen(path, TRUE);
         if (lf)
             version = lineFileReadAll(lf);
         else
             version = NULL;
         lineFileClose(&lf);
         }
     }
 return version;
 }
 
 void printDataVersion(char *database, struct trackDb *tdb)