7e89607805cac22b52143b23a45464759e66a957 braney Wed Sep 16 12:36:15 2026 -0700 docent: a login: step, with the account kept per hgcentral, refs #37892 hgCollection refuses a visitor who is not signed in -- hgCollection.c doMiddle, "You must be logged in to edit collections" -- and so does the saving half of hgSession. The suite has never had a logged-in page, and until now could not: the login cookie is validated against a salted hash (login.cookieSalt, hg/lib/wikiLink.c), so there is no cookie to hand the browser. A script that needs one of those pages has to sign in the way a person does. `login:` does that, through hgLogin's own form, and it takes no credentials and cannot be given any. They come from ~/.docentLogin (DOCENT_LOGIN_FILE overrides, DOCENT_LOGIN_USER + DOCENT_LOGIN_PASSWORD override both for one run), which is refused unless it is mode 0600 -- the rule hg/lib/hgConfig.c applies to hg.conf, for the same reason. Nothing prints a password. THE FILE IS KEYED BY HGCENTRAL DATABASE, not by server. An account is a row in gbMembers in one central, the way a named session is: genome-test, hgwdev, every hgwdev- sandbox and every ticket park read hgcentraltest and share one account, while hgwbeta reads hgcentralbeta and the RR reads hgcentral. So the file is one [hgcentraltest] section rather than a section per sandbox. Which central a server reads is READ from its hg.conf, following its includes the way hgConfig.c does, and not guessed from the host -- because a sandbox can point itself somewhere else and two on hgwdev do today: of the personal confs there, 45 set central.db=hgcentraltest, one sets hgcentralgsid and one hgcentralbeta. A server whose conf is on another machine falls back to a small table (the RR, the two mirrors, hgwbeta), and [default] catches the rest. A run redirected with DOCENT_TARGET looks up the server it is really driving. Two failures the step has to tell apart, and both cost a run to find: A WRONG PASSWORD IS A PERFECTLY GOOD PAGE. hgLogin answers one by drawing the same form again with a red message, so a step that just navigated on would leave every later step running logged out and the failure would surface somewhere else entirely. The step fails on #accountLoginForm still being there, and quotes what the page said. A RIGHT PASSWORD ARRIVES MID-REDIRECT. hgLogin answers one with a page that navigates ITSELF a moment later: returnToURL(150) at hgLogin.c:1160 writes setTimeout(function(){location=...}, 150). Returning while that timer is pending means the next step's goto: races it and the browser aborts one of the two, which arrives as a bare net::ERR_ABORTED on a URL that is completely fine. The step now waits for that redirect to land. The failure path is checked first, since that page never leaves hgLogin and there is no redirect to wait for. preflight reports the account as a fixture -- which central it resolved, which section it came from, and why it is unusable if it is -- so a missing password is caught before the browser starts. It attempts no login: a wrong password fails loudly at the step itself, which is the one thing preflight cannot do for it. The hg.conf reader is now in both docent.js and tests/preflight.js, beside the resolveTarget each of them already carries. Both say to keep the other in step. If that second copy is a copy too many, the two of them want a shared module. diff --git src/hg/utils/docent/tests/README.txt src/hg/utils/docent/tests/README.txt index 67494249425..ce7cce1fa77 100644 --- src/hg/utils/docent/tests/README.txt +++ src/hg/utils/docent/tests/README.txt @@ -176,23 +176,35 @@ visibility logic with hgTracks by COPY rather than by call: hg/hgCollection/hgCollection.c carries its own isParentVisible(), a verbatim copy of the one in hg/lib/trackHub.c. The copy in trackHub.c was caught by nine scripts in regress/ on the #37547 branch; the copy in hgCollection.c was found by grep afterwards, and would have dropped a container's children out of a saved collection in the same silent way. A test needs a `collection:` verb: the page puts tracks into a collection by dragging between two jsTrees, and `drag:` is the genomic drag-select on the track image, not that. Its buttons are #newCollection, #doNewCollection, #saveCollections and #discardChanges, which is enough to open and save one but not to put a track in it. A test that needs a stable server-side fixture (a hub, a custom track) should carry it in the script rather than assume something on disk. +The one fixture that cannot be carried anywhere is a login. hgCollection refuses a +visitor who is not signed in, and the login cookie is checked against a salted hash, so +a script that needs that page uses the `login:` step, and the step reads an account from +~/.docentLogin. That file is one [section] per HGCENTRAL DATABASE, because an account is +a row in gbMembers in one of them: genome-test, hgwdev, every sandbox and every ticket +park read hgcentraltest and share one account, while hgwbeta and the RR are separate sets +of accounts. Which central a server reads is read from its hg.conf rather than guessed +from the host -- a sandbox can point itself somewhere else, and two on hgwdev do today. +`make preflight` says which account and which central it resolved for the server being +driven, and refuses a file that is readable by group or other. No password is ever +printed and none can be written in a script. ../README.md under `login` has the format. + colorchecks is the one exception, and the reason is worth knowing before someone else hits it. `color:` has to address a ROW by name, and a custom track cannot be addressed by name at all: hgTracks assigns its row id (`ct__`), which is why customtrack asserts on label text instead of on `rows:`. So an inline custom track -- the self-contained way to get a known color onto the page -- is the one fixture this check cannot use. It reads ~/public_html/docentFixtures/itemRgbHub/ instead, which tests/regress/rm36212.xfail needs anyway, and which `make preflight` checks is still there.