1fbda5badde574c10884e5339fdda1f5b7495990 braney Thu Sep 24 13:45:30 2026 -0700 docent: regression script for the Sessions page Replace keeping who can load it, refs #38311 rm38311 saves a private session from the save card, saves over it with the private box unticked, and checks that the row still has its lock. It passes on hgwbeta (v504) and genome-test, and fails on hgw0 (v503). Docent changes it needed: - a fill: verb, to type into any form field - login: no longer dies when a navigation is still under way during its bad-password check, which is what broke it on ticket parks - a park is driven on its https port, because hgLogin posts its form to https:// on the port it was reached on; the parks' self-signed certificate is accepted on loopback targets only - hgw0 maps to hgcentral, and a park's https port finds its hg.conf diff --git src/hg/utils/docent/targetConf.js src/hg/utils/docent/targetConf.js index 3443057b4f0..e34e1b2159b 100644 --- src/hg/utils/docent/targetConf.js +++ src/hg/utils/docent/targetConf.js @@ -50,33 +50,35 @@ function hgConfFor(server) { let u; try { u = new URL(server); } catch (e) { return null; } const host = u.hostname; // 127.0.0.1 keeps its dots const name = host.split('.')[0]; // hgwdev-braney out of the FQDN if (name === 'hgwdev' || name === 'genome-test') return '/usr/local/apache/cgi-bin/hg.conf'; if (name.startsWith('hgwdev-')) // a sandbox or a demo browser return `/usr/local/apache/cgi-bin-${name.slice('hgwdev-'.length)}/hg.conf`; if ((host === '127.0.0.1' || host === 'localhost') && u.port) { // A ticket park from `ts`: its port is in the registry, and the frozen hg.conf sits // under the ticket's own directory. A park is the one target whose conf is NOT the // live sandbox's, which is the whole reason for parking it. const root = process.env.TS_ROOT || path.join(os.homedir(), 'ticketSandboxes'); let reg; try { reg = fs.readFileSync(path.join(root, 'ports.tsv'), 'utf8'); } catch (e) { return null; } + // The registry holds the http port; the same park answers https on that port + 1000. + const httpPort = String(u.protocol === 'https:' ? Number(u.port) - 1000 : Number(u.port)); for (const line of reg.split('\n')) { const f = line.split('\t'); - if (f[1] === u.port) return path.join(root, f[0], 'cgi-bin', 'hg.conf'); + if (f[1] === httpPort) return path.join(root, f[0], 'cgi-bin', 'hg.conf'); } } return null; } // hg.conf as hg/lib/hgConfig.c reads it: `include` pulls another file in relative to the // including one, `delete` drops a name, and a later assignment wins over an earlier one // (parseConfigLine hashAdds and cfgOption reads the most recently added). So the value // this returns is the EFFECTIVE one -- a sandbox conf that sets nothing still shows what // it inherits from the shared conf it includes. // // Callers print only the settings they name. The includes lead to hg.conf.private, which // holds database passwords. function readHgConf(file, out = new Map(), seen = new Set(), depth = 0) { if (depth > 10 || seen.has(file)) return out; @@ -92,30 +94,31 @@ for (const name of line.slice(6).trim().split(/\s+/)) out.delete(name); else { const eq = line.indexOf('='); if (eq > 0) out.set(line.slice(0, eq).trim(), line.slice(eq + 1).trim()); } } return out; } // Servers whose hg.conf is on another machine, so it cannot be read and has to be known. const CENTRAL_BY_HOST = { 'genome.ucsc.edu': 'hgcentral', 'genome-euro.ucsc.edu': 'hgcentral', // its own database of the same name 'genome-asia.ucsc.edu': 'hgcentral', // ... and so is this one 'hgwbeta.soe.ucsc.edu': 'hgcentralbeta', + 'hgw0.soe.ucsc.edu': 'hgcentral', // the RR node that takes a release first }; // Which hgcentral a server reads. Read from its hg.conf wherever that is possible, because // a sandbox may say so for itself: of the personal confs on hgwdev today, 45 set // central.db to hgcentraltest and two do not (hgcentralgsid, hgcentralbeta). function centralDbFor(server) { const file = hgConfFor(server); if (file) { const db = readHgConf(file).get('central.db'); if (db) return db; } try { return CENTRAL_BY_HOST[new URL(server).hostname] || null; } catch (e) { return null; } } // ---------- the account a `login:` step signs in with ----------